1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gnome-session.c - negotiate session and encode secrets
3 
4    Copyright (C) 2009 Stefan Walter
5 
6    The Gnome Keyring Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10 
11    The Gnome Keyring Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20 
21    Author: Stef Walter <stef@memberwebs.com>
22 */
23 
24 #include "config.h"
25 
26 #include "gkr-misc.h"
27 #include "gkr-session.h"
28 #include "gnome-keyring-private.h"
29 
30 #include <gcrypt.h>
31 
32 #include "egg/egg-dh.h"
33 #include "egg/egg-hkdf.h"
34 #include "egg/egg-libgcrypt.h"
35 #include "egg/egg-secure-memory.h"
36 
37 struct _GkrSession {
38 	gint refs;
39 	gchar *path;
40 	gpointer key;
41 	gsize n_key;
42 };
43 
44 G_LOCK_DEFINE_STATIC (session_globals);
45 static GkrSession *the_session;
46 
47 EGG_SECURE_DECLARE (session);
48 
49 static guchar*
pkcs7_pad_string_in_secure_memory(const gchar * string,gsize * n_padded)50 pkcs7_pad_string_in_secure_memory (const gchar *string, gsize *n_padded)
51 {
52 	gsize length, n_pad;
53 	guchar *padded;
54 
55 	length = strlen (string);
56 
57 	if (!g_utf8_validate (string, length, NULL))
58 		return NULL;
59 
60 	/* Pad the secret */
61 	*n_padded = ((length + 16) / 16) * 16;
62 	g_assert (length < *n_padded);
63 	g_assert (*n_padded > 0);
64 	n_pad = *n_padded - length;
65 	g_assert (n_pad > 0 && n_pad <= 16);
66 	padded = egg_secure_alloc (*n_padded);
67 	memcpy (padded, string, length);
68 	memset (padded + length, n_pad, n_pad);
69 	return padded;
70 }
71 
72 static gchar*
pkcs7_unpad_string_in_place(guchar * padded,gsize n_padded)73 pkcs7_unpad_string_in_place (guchar *padded, gsize n_padded)
74 {
75 	gsize n_pad, i;
76 
77 	if (n_padded == 0)
78 		return NULL;
79 
80 	n_pad = padded[n_padded - 1];
81 
82 	/* Validate the padding */
83 	if (n_pad == 0 || n_pad > 16)
84 		return NULL;
85 	if (n_pad > n_padded)
86 		return NULL;
87 	for (i = n_padded - n_pad; i < n_padded; ++i) {
88 		if (padded[i] != n_pad)
89 			return NULL;
90 	}
91 
92 	/* Null terminate */
93 	padded[n_padded - n_pad] = 0;
94 	if (!g_utf8_validate ((gchar*)padded, -1, NULL))
95 		return FALSE;
96 
97 	return (gchar*)padded;
98 }
99 
100 static GkrSession*
session_new(void)101 session_new (void)
102 {
103 	GkrSession *session = g_slice_new0 (GkrSession);
104 	session->refs = 1;
105 	return session;
106 }
107 
108 GkrSession*
gkr_session_ref(GkrSession * session)109 gkr_session_ref (GkrSession *session)
110 {
111 	g_assert (session);
112 	g_atomic_int_inc (&session->refs);
113 	return session;
114 }
115 
116 void
gkr_session_unref(gpointer data)117 gkr_session_unref (gpointer data)
118 {
119 	GkrSession *session = data;
120 
121 	if (!session)
122 		return;
123 
124 	if (!g_atomic_int_dec_and_test (&session->refs))
125 		return;
126 
127 	g_free (session->path);
128 	egg_secure_free (session->key);
129 	g_slice_free (GkrSession, session);
130 }
131 
132 const gchar*
gkr_session_get_path(GkrSession * session)133 gkr_session_get_path (GkrSession *session)
134 {
135 	g_assert (session);
136 	return session->path;
137 }
138 
139 static gboolean
decode_open_session_plain(DBusMessage * message,const char ** path)140 decode_open_session_plain (DBusMessage *message, const char **path)
141 {
142 	DBusMessageIter iter, variant;
143 	char *signature;
144 	gboolean equal;
145 
146 	g_assert (message);
147 	g_assert (path);
148 
149 	/* Parse the incomming message */
150 	if (!dbus_message_has_signature (message, "vo"))
151 		return FALSE;
152 	if (!dbus_message_iter_init (message, &iter))
153 		g_return_val_if_reached (FALSE);
154 	dbus_message_iter_recurse (&iter, &variant);
155 
156 	signature = dbus_message_iter_get_signature (&variant);
157 	equal = g_str_equal (signature, "s");
158 	dbus_free (signature);
159 	if (!equal)
160 		return FALSE;
161 
162 	if (!dbus_message_iter_next (&iter))
163 		g_return_val_if_reached (FALSE);
164 	dbus_message_iter_get_basic (&iter, path);
165 
166 	return TRUE;
167 }
168 
169 static void
on_open_session_plain(GkrOperation * op,DBusMessage * reply,gpointer user_data)170 on_open_session_plain (GkrOperation *op, DBusMessage *reply, gpointer user_data)
171 {
172 	GkrSession *session;
173 	const char *path;
174 
175 	if (gkr_operation_handle_errors (op, reply))
176 		return;
177 
178 	/* Parse the result from OpenSession */
179 	if (!decode_open_session_plain (reply, &path)) {
180 		g_message ("received an invalid response to Service.OpenSession()");
181 		gkr_operation_complete (op, GNOME_KEYRING_RESULT_IO_ERROR);
182 		return;
183 	}
184 
185 	session = session_new ();
186 	session->path = g_strdup (path);
187 	session->key = NULL;
188 	session->n_key = 0;
189 
190 	G_LOCK (session_globals);
191 	{
192 		if (the_session)
193 			gkr_session_unref (the_session);
194 		the_session = gkr_session_ref (session);
195 	}
196 	G_UNLOCK (session_globals);
197 
198 	gkr_callback_invoke_op_session (gkr_operation_pop (op), session);
199 	gkr_session_unref (session);
200 }
201 
202 static void
session_negotiate_plain(GkrOperation * op)203 session_negotiate_plain (GkrOperation *op)
204 {
205 	DBusMessageIter iter, variant;
206 	const char *algorithm = "plain";
207 	const char *empty = "";
208 	DBusMessage *req;
209 
210 	g_assert (op);
211 
212 	req = dbus_message_new_method_call (gkr_service_name, SERVICE_PATH,
213 	                                    SERVICE_INTERFACE, "OpenSession");
214 	dbus_message_iter_init_append (req, &iter);
215 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &algorithm);
216 	dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "s", &variant);
217 	dbus_message_iter_append_basic (&variant, DBUS_TYPE_STRING, &empty);
218 	dbus_message_iter_close_container (&iter, &variant);
219 
220 	gkr_operation_push (op, on_open_session_plain, GKR_CALLBACK_OP_MSG, NULL, NULL);
221 	gkr_operation_request (op, req);
222 	dbus_message_unref (req);
223 }
224 
225 static gboolean
decode_open_session_aes(DBusMessage * message,gcry_mpi_t * peer,const char ** path)226 decode_open_session_aes (DBusMessage *message, gcry_mpi_t *peer, const char **path)
227 {
228 	DBusMessageIter iter, variant, array;
229 	char *signature;
230 	gcry_error_t gcry;
231 	guchar *buffer;
232 	gboolean equal;
233 	int n_buffer;
234 
235 	g_assert (message);
236 	g_assert (peer);
237 	g_assert (path);
238 
239 	/* Parse the incomming message */
240 	if (!dbus_message_has_signature (message, "vo"))
241 		return FALSE;
242 	if (!dbus_message_iter_init (message, &iter))
243 		g_return_val_if_reached (FALSE);
244 	dbus_message_iter_recurse (&iter, &variant);
245 
246 	signature = dbus_message_iter_get_signature (&variant);
247 	equal = g_str_equal (signature, "ay");
248 	dbus_free (signature);
249 	if (!equal)
250 		return FALSE;
251 
252 	dbus_message_iter_recurse (&variant, &array);
253 	dbus_message_iter_get_fixed_array (&array, &buffer, &n_buffer);
254 	if (!dbus_message_iter_next (&iter))
255 		g_return_val_if_reached (FALSE);
256 	dbus_message_iter_get_basic (&iter, path);
257 
258 	gcry = gcry_mpi_scan (peer, GCRYMPI_FMT_USG, buffer, n_buffer, NULL);
259 	return (gcry == 0);
260 }
261 
262 static void
on_open_session_aes(GkrOperation * op,DBusMessage * reply,gpointer user_data)263 on_open_session_aes (GkrOperation *op, DBusMessage *reply, gpointer user_data)
264 {
265 	gcry_mpi_t priv, prime, peer;
266 	GkrSession *session;
267 	const char *path;
268 	gpointer ikm;
269 	gsize n_ikm;
270 
271 	g_assert (op);
272 	g_assert (user_data);
273 
274 	/* If AES is not supported then try plain method */
275 	if (dbus_message_is_error (reply, DBUS_ERROR_NOT_SUPPORTED)) {
276 		session_negotiate_plain (op);
277 		return;
278 	}
279 
280 	/* Handle any other errors */
281 	if (gkr_operation_handle_errors (op, reply))
282 		return;
283 
284 	/* Parse the result from OpenSession */
285 	if (!decode_open_session_aes (reply, &peer, &path)) {
286 		g_message ("received an invalid response to Service.OpenSession()");
287 		gkr_operation_complete (op, GNOME_KEYRING_RESULT_IO_ERROR);
288 		return;
289 	}
290 
291 	if (!egg_dh_default_params ("ietf-ike-grp-modp-1024", &prime, NULL))
292 		g_return_if_reached ();
293 
294 	/* Generate the actual secret */
295 	priv = user_data;
296 	ikm = egg_dh_gen_secret (peer, priv, prime, &n_ikm);
297 
298 	gcry_mpi_release (peer);
299 	gcry_mpi_release (prime);
300 
301 	if (ikm == NULL) {
302 		g_message ("couldn't negotiate a valid session key");
303 		gkr_operation_complete (op, GNOME_KEYRING_RESULT_IO_ERROR);
304 		return;
305 	}
306 
307 	session = session_new ();
308 	session->path = g_strdup (path);
309 	session->n_key = 16;
310 
311 	/* Now digest this into our aes key */
312 	session->key = egg_secure_alloc (session->n_key);
313 	if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0,
314 	                       session->key, session->n_key))
315 		g_return_if_reached ();
316 	egg_secure_free (ikm);
317 
318 	G_LOCK (session_globals);
319 	{
320 		if (the_session)
321 			gkr_session_unref (the_session);
322 		the_session = gkr_session_ref (session);
323 	}
324 	G_UNLOCK (session_globals);
325 
326 	gkr_callback_invoke_op_session (gkr_operation_pop (op), session);
327 	gkr_session_unref (session);
328 }
329 
330 static void
session_negotiate_aes(GkrOperation * op)331 session_negotiate_aes (GkrOperation *op)
332 {
333 	const char *algorithm = "dh-ietf1024-sha256-aes128-cbc-pkcs7";
334 	DBusMessageIter iter, variant, array;
335 	gcry_mpi_t prime, base, pub, priv;
336 	gboolean ret;
337 	guchar *buffer;
338 	gsize n_buffer;
339 	gcry_error_t gcry;
340 	DBusMessage *req;
341 
342 	g_assert (op);
343 
344 	egg_libgcrypt_initialize ();
345 
346 	prime = base = pub = priv = NULL;
347 	ret = egg_dh_default_params ("ietf-ike-grp-modp-1024", &prime, &base) &&
348 	      egg_dh_gen_pair (prime, base, 0, &pub, &priv);
349 
350 	gcry_mpi_release (prime);
351 	gcry_mpi_release (base);
352 
353 	if (ret == TRUE) {
354 		req = dbus_message_new_method_call (gkr_service_name, SERVICE_PATH,
355 		                                    SERVICE_INTERFACE, "OpenSession");
356 
357 		dbus_message_iter_init_append (req, &iter);
358 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &algorithm);
359 		dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "ay", &variant);
360 		dbus_message_iter_open_container (&variant, DBUS_TYPE_ARRAY, "y", &array);
361 
362 		gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer, pub);
363 		g_return_if_fail (gcry == 0);
364 		dbus_message_iter_append_fixed_array (&array, DBUS_TYPE_BYTE, &buffer, n_buffer);
365 		gcry_free (buffer);
366 
367 		dbus_message_iter_close_container (&variant, &array);
368 		dbus_message_iter_close_container (&iter, &variant);
369 
370 		gkr_operation_push (op, on_open_session_aes, GKR_CALLBACK_OP_MSG,
371 		                    priv, (GDestroyNotify)gcry_mpi_release);
372 		priv = NULL;
373 
374 		gkr_operation_request (op, req);
375 		dbus_message_unref (req);
376 	}
377 
378 	gcry_mpi_release (pub);
379 	gcry_mpi_release (priv);
380 
381 	if (ret == FALSE)
382 		gkr_operation_complete_later (op, GNOME_KEYRING_RESULT_IO_ERROR);
383 }
384 
385 void
gkr_session_negotiate(GkrOperation * op)386 gkr_session_negotiate (GkrOperation *op)
387 {
388 	GkrSession *session = NULL;
389 
390 	G_LOCK(session_globals);
391 	{
392 		if (the_session)
393 			session = gkr_session_ref (the_session);
394 	}
395 	G_UNLOCK(session_globals);
396 
397 	/* If we have a session just call through to the next step. */
398 	if (session) {
399 		gkr_callback_invoke_op_session (gkr_operation_pop (op), session);
400 		gkr_session_unref (session);
401 		return;
402 	}
403 
404 	/* Try to start a new AES session */
405 	session_negotiate_aes (op);
406 }
407 
408 void
gkr_session_clear(void)409 gkr_session_clear (void)
410 {
411 	G_LOCK (session_globals);
412 	{
413 		if (the_session) {
414 			gkr_session_unref (the_session);
415 			the_session = NULL;
416 		}
417 	}
418 	G_UNLOCK (session_globals);
419 }
420 
421 static gboolean
session_encode_secret(DBusMessageIter * iter,const gchar * path,gconstpointer parameter,gsize n_parameter,gconstpointer secret,gsize n_secret)422 session_encode_secret (DBusMessageIter *iter, const gchar *path, gconstpointer parameter,
423                        gsize n_parameter, gconstpointer secret, gsize n_secret)
424 {
425 	DBusMessageIter struc, array;
426 	const gchar *content_type = "text/plain; charset=utf8";
427 
428 	/* Write out the result message */
429 	dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &struc);
430 	dbus_message_iter_append_basic (&struc, DBUS_TYPE_OBJECT_PATH, &path);
431 	dbus_message_iter_open_container (&struc, DBUS_TYPE_ARRAY, "y", &array);
432 	dbus_message_iter_append_fixed_array (&array, DBUS_TYPE_BYTE, &parameter, n_parameter);
433 	dbus_message_iter_close_container (&struc, &array);
434 	dbus_message_iter_open_container (&struc, DBUS_TYPE_ARRAY, "y", &array);
435 	dbus_message_iter_append_fixed_array (&array, DBUS_TYPE_BYTE, &secret, n_secret);
436 	dbus_message_iter_close_container (&struc, &array);
437 	dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING, &content_type);
438 	dbus_message_iter_close_container (iter, &struc);
439 
440 	return TRUE;
441 }
442 
443 static gboolean
session_encode_plain_secret(GkrSession * session,DBusMessageIter * iter,const gchar * secret)444 session_encode_plain_secret (GkrSession *session, DBusMessageIter *iter, const gchar* secret)
445 {
446 	g_assert (session);
447 	g_assert (iter);
448 	g_assert (secret);
449 
450 	return session_encode_secret (iter, session->path, "", 0, secret, strlen (secret));
451 }
452 
453 static gboolean
session_encode_aes_secret(GkrSession * session,DBusMessageIter * iter,const gchar * secret)454 session_encode_aes_secret (GkrSession *session, DBusMessageIter *iter, const gchar* secret)
455 {
456 	gcry_cipher_hd_t cih;
457 	guchar *padded;
458 	gsize n_padded, pos;
459 	gcry_error_t gcry;
460 	gpointer iv;
461 
462 	g_assert (session);
463 	g_assert (iter);
464 	g_assert (secret);
465 
466 	/* Create the cipher */
467 	gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
468 	if (gcry != 0) {
469 		g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry));
470 		return FALSE;
471 	}
472 
473 	/* Perform the encoding here */
474 	padded = pkcs7_pad_string_in_secure_memory (secret, &n_padded);
475 	if (!padded) {
476 		g_warning ("couldn't encode secret for sending to service: invalid string");
477 		gcry_cipher_close (cih);
478 		return FALSE;
479 	}
480 
481 	/* Setup the IV */
482 	iv = g_malloc0 (16);
483 	gcry_create_nonce (iv, 16);
484 	gcry = gcry_cipher_setiv (cih, iv, 16);
485 	g_return_val_if_fail (gcry == 0, FALSE);
486 
487 	/* Setup the key */
488 	gcry = gcry_cipher_setkey (cih, session->key, session->n_key);
489 	g_return_val_if_fail (gcry == 0, FALSE);
490 
491 	/* Perform the encryption */
492 	for (pos = 0; pos < n_padded; pos += 16) {
493 		gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, 16, NULL, 0);
494 		g_return_val_if_fail (gcry == 0, FALSE);
495 	}
496 
497 	gcry_cipher_close (cih);
498 
499 	if (!session_encode_secret (iter, session->path, iv, 16, padded, n_padded))
500 		g_return_val_if_reached (FALSE);
501 
502 	egg_secure_clear (padded, n_padded);
503 	egg_secure_free (padded);
504 	g_free (iv);
505 
506 	return TRUE;
507 }
508 
509 gboolean
gkr_session_encode_secret(GkrSession * session,DBusMessageIter * iter,const gchar * secret)510 gkr_session_encode_secret (GkrSession *session, DBusMessageIter *iter, const gchar* secret)
511 {
512 	g_assert (session);
513 	g_assert (iter);
514 
515 	if (!secret)
516 		secret = "";
517 
518 	if (session->key)
519 		return session_encode_aes_secret (session, iter, secret);
520 	else
521 		return session_encode_plain_secret (session, iter, secret);
522 }
523 
524 static gboolean
session_decode_secret(DBusMessageIter * iter,const char ** path,gconstpointer * parameter,gsize * n_parameter,gconstpointer * secret,gsize * n_secret)525 session_decode_secret (DBusMessageIter *iter, const char **path, gconstpointer *parameter,
526                        gsize *n_parameter, gconstpointer *secret, gsize *n_secret)
527 {
528 	DBusMessageIter struc, array;
529 	int n_elements;
530 
531 	if (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_STRUCT)
532 		return FALSE;
533 	dbus_message_iter_recurse (iter, &struc);
534 
535 	if (dbus_message_iter_get_arg_type (&struc) != DBUS_TYPE_OBJECT_PATH)
536 		return FALSE;
537 	dbus_message_iter_get_basic (&struc, path);
538 
539 	if (!dbus_message_iter_next (&struc) ||
540 	    dbus_message_iter_get_arg_type (&struc) != DBUS_TYPE_ARRAY ||
541 	    dbus_message_iter_get_element_type (&struc) != DBUS_TYPE_BYTE)
542 		return FALSE;
543 	dbus_message_iter_recurse (&struc, &array);
544 	dbus_message_iter_get_fixed_array (&array, parameter, &n_elements);
545 	*n_parameter = n_elements;
546 
547 	if (!dbus_message_iter_next (&struc) ||
548 	    dbus_message_iter_get_arg_type (&struc) != DBUS_TYPE_ARRAY ||
549 	    dbus_message_iter_get_element_type (&struc) != DBUS_TYPE_BYTE)
550 		return FALSE;
551 	dbus_message_iter_recurse (&struc, &array);
552 	dbus_message_iter_get_fixed_array (&array, secret, &n_elements);
553 	*n_secret = n_elements;
554 
555 	/*
556 	 * content_type: We have no use for the content-type, but check
557 	 * that it's there...
558 	 */
559 	if (!dbus_message_iter_next (&struc) ||
560 	    dbus_message_iter_get_arg_type (&struc) != DBUS_TYPE_STRING)
561 		return FALSE;
562 
563 	return TRUE;
564 }
565 
566 static gboolean
session_decode_plain_secret(GkrSession * session,DBusMessageIter * iter,gchar ** result)567 session_decode_plain_secret (GkrSession *session, DBusMessageIter *iter, gchar **result)
568 {
569 	gconstpointer parameter, secret;
570 	gsize n_parameter, n_secret;
571 	const char *path;
572 
573 	g_assert (session);
574 	g_assert (iter);
575 	g_assert (result);
576 
577 	if (!session_decode_secret (iter, &path, &parameter, &n_parameter, &secret, &n_secret))
578 		return FALSE;
579 
580 	if (!g_str_equal (path, session->path)) {
581 		g_message ("received a secret encoded with wrong session");
582 		return FALSE;
583 	}
584 
585 	if (n_parameter != 0) {
586 		g_message ("received a plain secret structure with invalid parameter");
587 		return FALSE;
588 	}
589 
590 	if (!g_utf8_validate (secret, n_secret, NULL)) {
591 		g_message ("received a secret that was not utf8");
592 		return FALSE;
593 	}
594 
595 	*result = egg_secure_alloc (n_secret + 1);
596 	memcpy (*result, secret, n_secret);
597 	return TRUE;
598 }
599 
600 static gboolean
session_decode_aes_secret(GkrSession * session,DBusMessageIter * iter,gchar ** result)601 session_decode_aes_secret (GkrSession *session, DBusMessageIter *iter, gchar **result)
602 {
603 	gconstpointer parameter, secret;
604 	gsize n_parameter, n_secret, n_padded;
605 	const char *path;
606 	gcry_error_t gcry;
607 	gcry_cipher_hd_t cih;
608 	guchar *padded;
609 	gsize pos;
610 
611 	g_assert (session);
612 	g_assert (iter);
613 	g_assert (result);
614 
615 	if (!session_decode_secret (iter, &path, &parameter, &n_parameter, &secret, &n_secret))
616 		return FALSE;
617 
618 	if (!g_str_equal (path, session->path)) {
619 		g_message ("received a secret encoded with wrong session");
620 		return FALSE;
621 	}
622 
623 	if (n_parameter != 16) {
624 		g_message ("received an encrypted secret structure with invalid parameter");
625 		return FALSE;
626 	}
627 
628 	if (n_secret == 0 || n_secret % 16 != 0) {
629 		g_message ("received an encrypted secret structure with bad secret length");
630 		return FALSE;
631 	}
632 
633 	gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
634 	if (gcry != 0) {
635 		g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry));
636 		return FALSE;
637 	}
638 
639 	gcry = gcry_cipher_setiv (cih, parameter, n_parameter);
640 	g_return_val_if_fail (gcry == 0, FALSE);
641 
642 	gcry = gcry_cipher_setkey (cih, session->key, session->n_key);
643 	g_return_val_if_fail (gcry == 0, FALSE);
644 
645 	/* Copy the memory buffer */
646 	n_padded = n_secret;
647 	padded = egg_secure_alloc (n_padded);
648 	memcpy (padded, secret, n_padded);
649 
650 	/* Perform the decryption */
651 	for (pos = 0; pos < n_padded; pos += 16) {
652 		gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, 16, NULL, 0);
653 		g_return_val_if_fail (gcry == 0, FALSE);
654 	}
655 
656 	gcry_cipher_close (cih);
657 
658 	/* Unpad the resulting value */
659 	*result = pkcs7_unpad_string_in_place (padded, n_padded);
660 	if (!*result) {
661 		egg_secure_clear (padded, n_padded);
662 		egg_secure_free (padded);
663 		g_message ("received an invalid, unencryptable, or non-utf8 secret");
664 		return FALSE;
665 	}
666 
667 	return TRUE;
668 }
669 
670 gboolean
gkr_session_decode_secret(GkrSession * session,DBusMessageIter * iter,gchar ** secret)671 gkr_session_decode_secret (GkrSession *session, DBusMessageIter *iter, gchar** secret)
672 {
673 	g_assert (session);
674 	g_assert (iter);
675 	g_assert (secret);
676 
677 	if (session->key)
678 		return session_decode_aes_secret (session, iter, secret);
679 	else
680 		return session_decode_plain_secret (session, iter, secret);
681 }
682