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, ¶meter, 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, ¶meter, &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, ¶meter, &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