1 /* passphrase.c - Get a passphrase
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3 * 2005 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
30 #if !defined(HAVE_DOSISH_SYSTEM) && !defined(__riscos__)
31 #include <sys/socket.h>
41 #ifdef HAVE_LANGINFO_CODESET
54 #ifdef ENABLE_AGENT_SUPPORT
56 #endif /*ENABLE_AGENT_SUPPORT*/
58 static char *fd_passwd
= NULL
;
59 static char *next_pw
= NULL
;
60 static char *last_pw
= NULL
;
62 static void hash_passphrase( DEK
*dek
, char *pw
, STRING2KEY
*s2k
, int create
);
65 have_static_passphrase()
73 * Set the passphrase to be used for the next query and only for the next
77 set_next_passphrase( const char *s
)
82 next_pw
= xmalloc_secure( strlen(s
)+1 );
88 * Get the last passphrase used in passphrase_to_dek.
89 * Note: This removes the passphrase from this modules and
90 * the caller must free the result. May return NULL:
100 /* As if we had used the passphrase - make it the last_pw. */
102 next_to_last_passphrase(void)
111 /* Here's an interesting question: since this passphrase was passed in
112 on the command line, is there really any point in using secure
113 memory for it? I'm going with 'yes', since it doesn't hurt, and
114 might help in some small way (swapping). */
117 set_passphrase_from_string(const char *pass
)
120 fd_passwd
= xmalloc_secure(strlen(pass
)+1);
121 strcpy(fd_passwd
,pass
);
126 read_passphrase_from_fd( int fd
)
132 { /* Not used but we have to do a dummy read, so that it won't end
133 up at the begin of the message if the quite usual trick to
134 prepend the passphtrase to the message is used. */
137 while (!(read (fd
, buf
, 1) != 1 || *buf
== '\n' ))
144 tty_printf("Reading passphrase from file descriptor %d ...", fd
);
145 for (pw
= NULL
, i
= len
= 100; ; i
++ )
151 pw
= xmalloc_secure( len
);
160 if (read( fd
, pw
+i
, 1) != 1 || pw
[i
] == '\n' )
165 tty_printf("\b\b\b \n" );
173 #ifdef ENABLE_AGENT_SUPPORT
174 /* Send one option to the gpg-agent. */
176 agent_send_option (assuan_context_t ctx
, const char *name
, const char *value
)
181 if (!value
|| !*value
)
182 return 0; /* Avoid sending empty option values. */
184 line
= xmalloc (7 + strlen (name
) + 1 + strlen (value
) + 1);
185 strcpy (stpcpy (stpcpy (stpcpy (line
, "OPTION "), name
), "="), value
);
186 rc
= assuan_transact (ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
191 /* Send all required options to the gpg-agent. */
193 agent_send_all_options (assuan_context_t ctx
)
195 char *dft_display
= NULL
;
196 const char *dft_ttyname
= NULL
;
197 char *dft_ttytype
= NULL
;
202 dft_display
= getenv ("DISPLAY");
203 if (opt
.display
|| dft_display
)
205 if (agent_send_option (ctx
, "display",
206 opt
.display
? opt
.display
: dft_display
))
214 dft_ttyname
= getenv ("GPG_TTY");
215 if ((!dft_ttyname
|| !*dft_ttyname
) && (tmp
=ttyname (0)))
217 if ((!dft_ttyname
|| !*dft_ttyname
) && (tmp
=tty_get_ttyname ()))
220 if (opt
.ttyname
|| dft_ttyname
)
222 if (agent_send_option (ctx
, "ttyname",
223 opt
.ttyname
? opt
.ttyname
: dft_ttyname
))
227 dft_ttytype
= getenv ("TERM");
228 if (opt
.ttytype
|| (dft_ttyname
&& dft_ttytype
))
230 if (agent_send_option (ctx
, "ttytype",
231 opt
.ttyname
? opt
.ttytype
: dft_ttytype
))
235 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
236 old_lc
= setlocale (LC_CTYPE
, NULL
);
238 old_lc
= xstrdup (old_lc
);
239 dft_lc
= setlocale (LC_CTYPE
, "");
241 if (opt
.lc_ctype
|| (dft_ttyname
&& dft_lc
))
243 rc
= agent_send_option (ctx
, "lc-ctype",
244 opt
.lc_ctype
? opt
.lc_ctype
: dft_lc
);
246 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
249 setlocale (LC_CTYPE
, old_lc
);
256 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
257 old_lc
= setlocale (LC_MESSAGES
, NULL
);
259 old_lc
= xstrdup (old_lc
);
260 dft_lc
= setlocale (LC_MESSAGES
, "");
262 if (opt
.lc_messages
|| (dft_ttyname
&& dft_lc
))
264 rc
= agent_send_option (ctx
, "lc-messages",
265 opt
.lc_messages
? opt
.lc_messages
: dft_lc
);
267 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
270 setlocale (LC_MESSAGES
, old_lc
);
276 #endif /*ENABLE_AGENT_SUPPORT*/
280 * Open a connection to the agent and initializes the connection.
281 * Returns: -1 on error; on success an Assuan context for that
282 * connection is returned. With TRY set to true, no error messages
283 * are printed and the use of the agent won't get disabled on failure.
284 * If ORIG_CODESET is not NULL, the function will swithc the codeset
285 * back to that one before printing error messages.
287 #ifdef ENABLE_AGENT_SUPPORT
289 agent_open (int try, const char *orig_codeset
)
292 assuan_context_t ctx
;
297 if (opt
.gpg_agent_info
)
298 infostr
= xstrdup (opt
.gpg_agent_info
);
301 infostr
= getenv ( "GPG_AGENT_INFO" );
302 if (!infostr
|| !*infostr
)
308 bind_textdomain_codeset (PACKAGE
, orig_codeset
);
309 #endif /*ENABLE_NLS*/
310 log_info (_("gpg-agent is not available in this session\n"));
315 infostr
= xstrdup ( infostr
);
318 if ( !(p
= strchr (infostr
, PATHSEP_C
)) || p
== infostr
)
324 bind_textdomain_codeset (PACKAGE
, orig_codeset
);
325 #endif /*ENABLE_NLS*/
326 log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
334 while (*p
&& *p
!= PATHSEP_C
)
336 prot
= *p
? atoi (p
+1) : 0;
343 bind_textdomain_codeset (PACKAGE
, orig_codeset
);
344 #endif /*ENABLE_NLS*/
345 log_error (_("gpg-agent protocol version %d is not supported\n"),
353 rc
= assuan_socket_connect (&ctx
, infostr
, pid
);
360 bind_textdomain_codeset (PACKAGE
, orig_codeset
);
361 #endif /*ENABLE_NLS*/
362 log_error ( _("can't connect to `%s': %s\n"),
363 infostr
, assuan_strerror (rc
));
371 if (agent_send_all_options (ctx
))
377 bind_textdomain_codeset (PACKAGE
, orig_codeset
);
378 #endif /*ENABLE_NLS*/
379 log_error (_("problem with the agent - disabling agent use\n"));
382 assuan_disconnect (ctx
);
388 #endif/*ENABLE_AGENT_SUPPORT*/
391 #ifdef ENABLE_AGENT_SUPPORT
393 agent_close (assuan_context_t ctx
)
395 assuan_disconnect (ctx
);
397 #endif /*ENABLE_AGENT_SUPPORT*/
400 /* Copy the text ATEXT into the buffer P and do plus '+' and percent
401 escaping. Note that the provided buffer needs to be 3 times the
402 size of ATEXT plus 1. Returns a pointer to the leading Nul in P. */
403 #ifdef ENABLE_AGENT_SUPPORT
405 percent_plus_escape (char *p
, const char *atext
)
407 const unsigned char *s
;
409 for (s
=atext
; *s
; s
++)
411 if (*s
< ' ' || *s
== '+')
413 sprintf (p
, "%%%02X", *s
);
424 #endif /*ENABLE_AGENT_SUPPORT*/
427 #ifdef ENABLE_AGENT_SUPPORT
429 /* Object for the agent_okay_cb function. */
430 struct agent_okay_cb_s
{
434 /* A callback used to get the passphrase from the okay line. See
435 agent-get_passphrase for details. LINE is the rest of the OK
436 status line without leading white spaces. */
437 static assuan_error_t
438 agent_okay_cb (void *opaque
, const char *line
)
440 struct agent_okay_cb_s
*parm
= opaque
;
443 /* Note: If the malloc below fails we won't be able to wipe the
444 memory at LINE given the current implementation of the Assuan
445 code. There is no easy ay around this w/o adding a lot of more
446 memory function code to allow wiping arbitrary stuff on memory
448 parm
->pw
= xmalloc_secure (strlen (line
)/2+2);
450 for (i
=0; hexdigitp (line
) && hexdigitp (line
+1); line
+= 2)
451 parm
->pw
[i
++] = xtoi_2 (line
);
455 #endif /*ENABLE_AGENT_SUPPORT*/
460 * Ask the GPG Agent for the passphrase.
461 * Mode 0: Allow cached passphrase
462 * 1: No cached passphrase FIXME: Not really implemented
463 * 2: Ditto, but change the text to "repeat entry"
465 * Note that TRYAGAIN_TEXT must not be translated. If canceled is not
466 * NULL, the function does set it to 1 if the user canceled the
467 * operation. If CACHEID is not NULL, it will be used as the cacheID
468 * for the gpg-agent; if is NULL and a key fingerprint can be
469 * computed, this will be used as the cacheid.
472 agent_get_passphrase ( u32
*keyid
, int mode
, const char *cacheid
,
473 const char *tryagain_text
,
474 const char *custom_description
,
475 const char *custom_prompt
, int *canceled
)
477 #ifdef ENABLE_AGENT_SUPPORT
479 assuan_context_t ctx
= NULL
;
481 PKT_public_key
*pk
= xmalloc_clear( sizeof *pk
);
482 byte fpr
[MAX_FINGERPRINT_LEN
];
484 char *orig_codeset
= NULL
;
489 #if MAX_FINGERPRINT_LEN < 20
490 #error agent needs a 20 byte fingerprint
493 memset (fpr
, 0, MAX_FINGERPRINT_LEN
);
494 if( keyid
&& get_pubkey( pk
, keyid
) )
497 free_public_key( pk
);
498 pk
= NULL
; /* oops: no key for some reason */
502 /* The Assuan agent protocol requires us to transmit utf-8 strings */
503 orig_codeset
= bind_textdomain_codeset (PACKAGE
, NULL
);
504 #ifdef HAVE_LANGINFO_CODESET
506 orig_codeset
= nl_langinfo (CODESET
);
509 { /* We only switch when we are able to restore the codeset later. */
510 orig_codeset
= xstrdup (orig_codeset
);
511 if (!bind_textdomain_codeset (PACKAGE
, "utf-8"))
516 if ( !(ctx
= agent_open (0, orig_codeset
)) )
519 if (custom_description
)
520 atext
= native_to_utf8 (custom_description
);
521 else if ( !mode
&& pk
&& keyid
)
525 const char *algo_name
= pubkey_algo_to_string ( pk
->pubkey_algo
);
532 #define KEYIDSTRING _(" (main key ID %s)")
534 maink
= xmalloc ( strlen (KEYIDSTRING
) + keystrlen() + 20 );
535 if( keyid
[2] && keyid
[3] && keyid
[0] != keyid
[2]
536 && keyid
[1] != keyid
[3] )
537 sprintf( maink
, KEYIDSTRING
, keystr(&keyid
[2]) );
541 uid
= get_user_id ( keyid
, &uidlen
);
542 timestr
= strtimestamp (pk
->timestamp
);
546 #define PROMPTSTRING _("You need a passphrase to unlock the secret" \
549 "%u-bit %s key, ID %s, created %s%s\n" )
551 atext
= xmalloc ( 100 + strlen (PROMPTSTRING
)
552 + uidlen
+ 15 + strlen(algo_name
) + keystrlen()
553 + strlen (timestr
) + strlen (maink
) );
554 sprintf (atext
, PROMPTSTRING
,
556 nbits_from_pk (pk
), algo_name
, keystr(&keyid
[0]), timestr
,
565 fingerprint_from_pk( pk
, fpr
, &dummy
);
571 atext
= xstrdup ( _("Repeat passphrase\n") );
573 atext
= xstrdup ( _("Enter passphrase\n") );
578 struct agent_okay_cb_s okay_cb_parm
;
583 tryagain_text
= _(tryagain_text
);
585 /* We allocate 23 times the needed space for thye texts so that
586 there is enough space for escaping. */
587 line
= xmalloc (15 + 46
589 + 3*strlen (custom_prompt
? custom_prompt
:"")
590 + (cacheid
? (3*strlen (cacheid
)): 0)
591 + 3*strlen (tryagain_text
)
593 strcpy (line
, "GET_PASSPHRASE ");
595 if (!mode
&& cacheid
)
597 p
= percent_plus_escape (p
, cacheid
);
599 else if (!mode
&& have_fpr
)
601 for (i
=0; i
< 20; i
++, p
+=2 )
602 sprintf (p
, "%02X", fpr
[i
]);
605 *p
++ = 'X'; /* No caching. */
608 p
= percent_plus_escape (p
, tryagain_text
);
614 char *tmp
= native_to_utf8 (custom_prompt
);
615 p
= percent_plus_escape (p
, tmp
);
619 *p
++ = 'X'; /* Use the standard prompt. */
622 /* Copy description. */
623 percent_plus_escape (p
, atext
);
625 /* Call gpg-agent. */
626 memset (&okay_cb_parm
, 0, sizeof okay_cb_parm
);
627 rc
= assuan_transact2 (ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
628 agent_okay_cb
, &okay_cb_parm
);
631 xfree (atext
); atext
= NULL
;
634 assert (okay_cb_parm
.pw
);
635 pw
= okay_cb_parm
.pw
;
638 free_public_key( pk
);
641 bind_textdomain_codeset (PACKAGE
, orig_codeset
);
643 xfree (orig_codeset
);
646 else if (rc
&& (rc
& 0xffff) == 99)
648 /* 99 is GPG_ERR_CANCELED. */
649 log_info (_("cancelled by user\n") );
655 log_error (_("problem with the agent - disabling agent use\n"));
665 bind_textdomain_codeset (PACKAGE
, orig_codeset
);
666 xfree (orig_codeset
);
673 free_public_key( pk
);
675 #endif /*ENABLE_AGENT_SUPPORT*/
682 * Clear the cached passphrase. If CACHEID is not NULL, it will be
683 * used instead of a cache ID derived from KEYID.
686 passphrase_clear_cache ( u32
*keyid
, const char *cacheid
, int algo
)
688 #ifdef ENABLE_AGENT_SUPPORT
689 assuan_context_t ctx
= NULL
;
691 byte fpr
[MAX_FINGERPRINT_LEN
];
693 #if MAX_FINGERPRINT_LEN < 20
694 #error agent needs a 20 byte fingerprint
702 pk
= xcalloc (1, sizeof *pk
);
703 memset (fpr
, 0, MAX_FINGERPRINT_LEN
);
704 if( !keyid
|| get_pubkey( pk
, keyid
) )
706 goto failure
; /* oops: no key for some reason */
711 fingerprint_from_pk( pk
, fpr
, &dummy
);
717 if ( !(ctx
= agent_open (0, NULL
)) )
726 line
= xmalloc (17 + 3*strlen (cacheid
) + 2);
727 strcpy (line
, "CLEAR_PASSPHRASE ");
729 p
= percent_plus_escape (p
, cacheid
);
733 line
= xmalloc (17 + 40 + 2);
734 strcpy (line
, "CLEAR_PASSPHRASE ");
736 for (i
=0; i
< 20; i
++, p
+=2 )
737 sprintf (p
, "%02X", fpr
[i
]);
741 rc
= assuan_transact (ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
745 log_error (_("problem with the agent - disabling agent use\n"));
753 free_public_key( pk
);
754 #endif /*ENABLE_AGENT_SUPPORT*/
759 * Ask for a passphrase and return that string.
762 ask_passphrase (const char *description
,
763 const char *tryagain_text
,
764 const char *promptid
,
766 const char *cacheid
, int *canceled
)
773 if (!opt
.batch
&& description
)
775 if (strchr (description
, '%'))
777 char *tmp
= unescape_percent_string (description
);
778 tty_printf ("\n%s\n", tmp
);
782 tty_printf ("\n%s\n",description
);
788 pw
= agent_get_passphrase (NULL
, 0, cacheid
,
789 tryagain_text
, description
, prompt
,
800 pw
= xmalloc_secure (strlen(fd_passwd
)+1);
801 strcpy (pw
, fd_passwd
);
805 log_error(_("can't query passphrase in batch mode\n"));
810 tty_printf(_("%s.\n"), tryagain_text
);
811 pw
= cpr_get_hidden(promptid
? promptid
: "passphrase.ask",
812 prompt
?prompt
: _("Enter passphrase: ") );
817 write_status( STATUS_MISSING_PASSPHRASE
);
823 /* Return a new DEK object Using the string-to-key sepcifier S2K. Use
824 * KEYID and PUBKEY_ALGO to prompt the user.
826 MODE 0: Allow cached passphrase
827 1: Ignore cached passphrase
828 2: Ditto, but change the text to "repeat entry"
831 passphrase_to_dek( u32
*keyid
, int pubkey_algo
,
832 int cipher_algo
, STRING2KEY
*s2k
, int mode
,
833 const char *tryagain_text
, int *canceled
)
843 /* This is used for the old rfc1991 mode
844 * Note: This must match the code in encode.c with opt.rfc1991 set */
847 s2k
->hash_algo
= S2K_DIGEST_ALGO
;
850 /* If we do not have a passphrase available in NEXT_PW and status
851 information are request, we print them now. */
852 if( !next_pw
&& is_status_enabled() ) {
859 if( keyid
[2] && keyid
[3] ) {
860 used_kid
[0] = keyid
[2];
861 used_kid
[1] = keyid
[3];
864 used_kid
[0] = keyid
[0];
865 used_kid
[1] = keyid
[1];
868 us
= get_long_user_id_string( keyid
);
869 write_status_text( STATUS_USERID_HINT
, us
);
872 sprintf( buf
, "%08lX%08lX %08lX%08lX %d 0",
873 (ulong
)keyid
[0], (ulong
)keyid
[1],
874 (ulong
)used_kid
[0], (ulong
)used_kid
[1],
877 write_status_text( STATUS_NEED_PASSPHRASE
, buf
);
880 sprintf( buf
, "%d %d %d", cipher_algo
, s2k
->mode
, s2k
->hash_algo
);
881 write_status_text( STATUS_NEED_PASSPHRASE_SYM
, buf
);
885 /* If we do have a keyID, we do not have a passphrase available in
886 NEXT_PW, we are not running in batch mode and we do not want to
887 ignore the passphrase cache (mode!=1), print a prompt with
888 information on that key. */
889 if( keyid
&& !opt
.batch
&& !next_pw
&& mode
!=1 ) {
890 PKT_public_key
*pk
= xmalloc_clear( sizeof *pk
);
893 p
=get_user_id_native(keyid
);
895 tty_printf(_("You need a passphrase to unlock the secret key for\n"
896 "user: \"%s\"\n"),p
);
899 if( !get_pubkey( pk
, keyid
) ) {
900 const char *s
= gcry_pk_algo_name ( pk
->pubkey_algo
);
901 tty_printf( _("%u-bit %s key, ID %s, created %s"),
902 nbits_from_pk( pk
), s
?s
:"?", keystr(keyid
),
903 strtimestamp(pk
->timestamp
) );
904 if( keyid
[2] && keyid
[3] && keyid
[0] != keyid
[2]
905 && keyid
[1] != keyid
[3] )
910 tty_printf(_(" (subkey on main key ID %s)"),
914 tty_printf( _(" (main key ID %s)"), keystr(&keyid
[2]) );
921 free_public_key( pk
);
926 /* Simply return the passphrase we already have in NEXT_PW. */
930 else if ( opt
.use_agent
) {
931 /* Divert to the gpg-agent. */
932 pw
= agent_get_passphrase ( keyid
, mode
== 2? 1: 0, NULL
,
933 tryagain_text
, NULL
, NULL
, canceled
);
940 if( *pw
&& mode
== 2 ) {
941 char *pw2
= agent_get_passphrase ( keyid
, 2, NULL
, NULL
, NULL
,
953 if( strcmp(pw
, pw2
) ) {
961 else if( fd_passwd
) {
962 /* Return the passphrase we have store in FD_PASSWD. */
963 pw
= xmalloc_secure( strlen(fd_passwd
)+1 );
964 strcpy( pw
, fd_passwd
);
968 log_error(_("can't query passphrase in batch mode\n"));
969 pw
= xstrdup( "" ); /* return an empty passphrase */
972 /* Read the passphrase from the tty or the command-fd. */
973 pw
= cpr_get_hidden("passphrase.enter", _("Enter passphrase: ") );
975 if( mode
== 2 && !cpr_enabled() ) {
976 char *pw2
= cpr_get_hidden("passphrase.repeat",
977 _("Repeat passphrase: ") );
979 if( strcmp(pw
, pw2
) ) {
989 write_status( STATUS_MISSING_PASSPHRASE
);
991 /* Hash the passphrase and store it in a newly allocated DEK
992 object. Keep a copy of the passphrase in LAST_PW for use by
993 get_last_passphrase(). */
994 dek
= xmalloc_secure_clear ( sizeof *dek
);
995 dek
->algo
= cipher_algo
;
996 if( !*pw
&& mode
== 2 )
999 hash_passphrase( dek
, pw
, s2k
, mode
==2 );
1007 * Hash a passphrase using the supplied s2k. If create is true, create
1008 * a new salt or what else must be filled into the s2k for a new key.
1009 * always needs: dek->algo, s2k->mode, s2k->hash_algo.
1012 hash_passphrase( DEK
*dek
, char *pw
, STRING2KEY
*s2k
, int create
)
1017 int pwlen
= strlen(pw
);
1019 assert( s2k
->hash_algo
);
1020 dek
->keylen
= gcry_cipher_get_algo_keylen (dek
->algo
);
1021 if( !(dek
->keylen
> 0 && dek
->keylen
<= DIM(dek
->key
)) )
1024 if (gcry_md_open (&md
, s2k
->hash_algo
, 1))
1026 for(pass
=0; used
< dek
->keylen
; pass
++ ) {
1029 for(i
=0; i
< pass
; i
++ ) /* preset the hash context */
1030 gcry_md_putc (md
, 0 );
1033 if( s2k
->mode
== 1 || s2k
->mode
== 3 ) {
1034 int len2
= pwlen
+ 8;
1037 if( create
&& !pass
) {
1038 gcry_randomize (s2k
->salt
, 8, GCRY_STRONG_RANDOM
);
1039 if( s2k
->mode
== 3 )
1040 s2k
->count
= 96; /* 65536 iterations */
1043 if( s2k
->mode
== 3 ) {
1044 count
= (16ul + (s2k
->count
& 15)) << ((s2k
->count
>> 4) + 6);
1048 /* a little bit complicated because we need a ulong for count */
1049 while( count
> len2
) { /* maybe iterated+salted */
1050 gcry_md_write ( md
, s2k
->salt
, 8 );
1051 gcry_md_write ( md
, pw
, pwlen
);
1055 gcry_md_write ( md
, s2k
->salt
, count
);
1057 gcry_md_write ( md
, s2k
->salt
, 8 );
1059 gcry_md_write ( md
, pw
, count
);
1063 gcry_md_write ( md
, pw
, pwlen
);
1064 gcry_md_final( md
);
1065 i
= gcry_md_get_algo_dlen ( s2k
->hash_algo
);
1066 if( i
> dek
->keylen
- used
)
1067 i
= dek
->keylen
- used
;
1068 memcpy (dek
->key
+used
, gcry_md_read (md
, s2k
->hash_algo
), i
);