Line data Source code
1 : /* passphrase.c - Get a passphrase
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3 : * 2005, 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
4 : *
5 : * This file is part of GnuPG.
6 : *
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 3 of the License, or
10 : * (at your option) any later version.
11 : *
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.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <stddef.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <unistd.h>
27 : #include <assert.h>
28 : #include <errno.h>
29 : #ifdef HAVE_LOCALE_H
30 : #include <locale.h>
31 : #endif
32 : #ifdef HAVE_LANGINFO_CODESET
33 : #include <langinfo.h>
34 : #endif
35 :
36 : #include "gpg.h"
37 : #include "util.h"
38 : #include "options.h"
39 : #include "ttyio.h"
40 : #include "keydb.h"
41 : #include "main.h"
42 : #include "i18n.h"
43 : #include "status.h"
44 : #include "call-agent.h"
45 : #include "../common/shareddefs.h"
46 :
47 : static char *fd_passwd = NULL;
48 : static char *next_pw = NULL;
49 : static char *last_pw = NULL;
50 :
51 :
52 :
53 : /* Pack an s2k iteration count into the form specified in 2440. If
54 : we're in between valid values, round up. With value 0 return the
55 : old default. */
56 : unsigned char
57 436 : encode_s2k_iterations (int iterations)
58 : {
59 : gpg_error_t err;
60 436 : unsigned char c=0;
61 : unsigned char result;
62 : unsigned int count;
63 :
64 436 : if (!iterations)
65 : {
66 : unsigned long mycnt;
67 :
68 : /* Ask the gpg-agent for a useful iteration count. */
69 0 : err = agent_get_s2k_count (&mycnt);
70 0 : if (err || mycnt < 65536)
71 : {
72 : /* Don't print an error if an older agent is used. */
73 0 : if (err && gpg_err_code (err) != GPG_ERR_ASS_PARAMETER)
74 0 : log_error (_("problem with the agent: %s\n"), gpg_strerror (err));
75 : /* Default to 65536 which we used up to 2.0.13. */
76 0 : return 96;
77 : }
78 0 : else if (mycnt >= 65011712)
79 0 : return 255; /* Largest possible value. */
80 : else
81 0 : return encode_s2k_iterations ((int)mycnt);
82 : }
83 :
84 436 : if (iterations <= 1024)
85 0 : return 0; /* Command line arg compatibility. */
86 :
87 436 : if (iterations >= 65011712)
88 0 : return 255;
89 :
90 : /* Need count to be in the range 16-31 */
91 3052 : for (count=iterations>>6; count>=32; count>>=1)
92 2616 : c++;
93 :
94 436 : result = (c<<4)|(count-16);
95 :
96 436 : if (S2K_DECODE_COUNT(result) < iterations)
97 0 : result++;
98 :
99 436 : return result;
100 : }
101 :
102 :
103 : int
104 436 : have_static_passphrase()
105 : {
106 872 : return (!!fd_passwd
107 436 : && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK));
108 : }
109 :
110 : /* Return a static passphrase. The returned value is only valid as
111 : long as no other passphrase related function is called. NULL may
112 : be returned if no passphrase has been set; better use
113 : have_static_passphrase first. */
114 : const char *
115 0 : get_static_passphrase (void)
116 : {
117 0 : return fd_passwd;
118 : }
119 :
120 :
121 : /****************
122 : * Set the passphrase to be used for the next query and only for the next
123 : * one.
124 : */
125 : void
126 0 : set_next_passphrase( const char *s )
127 : {
128 0 : xfree(next_pw);
129 0 : next_pw = NULL;
130 0 : if ( s )
131 : {
132 0 : next_pw = xmalloc_secure( strlen(s)+1 );
133 0 : strcpy (next_pw, s );
134 : }
135 0 : }
136 :
137 : /****************
138 : * Get the last passphrase used in passphrase_to_dek.
139 : * Note: This removes the passphrase from this modules and
140 : * the caller must free the result. May return NULL:
141 : */
142 : char *
143 0 : get_last_passphrase()
144 : {
145 0 : char *p = last_pw;
146 0 : last_pw = NULL;
147 0 : return p;
148 : }
149 :
150 : /* Here's an interesting question: since this passphrase was passed in
151 : on the command line, is there really any point in using secure
152 : memory for it? I'm going with 'yes', since it doesn't hurt, and
153 : might help in some small way (swapping). */
154 :
155 : void
156 0 : set_passphrase_from_string(const char *pass)
157 : {
158 0 : xfree (fd_passwd);
159 0 : fd_passwd = xmalloc_secure(strlen(pass)+1);
160 0 : strcpy (fd_passwd, pass);
161 0 : }
162 :
163 :
164 : void
165 493 : read_passphrase_from_fd( int fd )
166 : {
167 : int i, len;
168 : char *pw;
169 :
170 493 : if ( !opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK)
171 : { /* Not used but we have to do a dummy read, so that it won't end
172 : up at the begin of the message if the quite usual trick to
173 : prepend the passphtrase to the message is used. */
174 : char buf[1];
175 :
176 0 : while (!(read (fd, buf, 1) != 1 || *buf == '\n' ))
177 : ;
178 0 : *buf = 0;
179 493 : return;
180 : }
181 :
182 7640 : for (pw = NULL, i = len = 100; ; i++ )
183 : {
184 7640 : if (i >= len-1 )
185 : {
186 493 : char *pw2 = pw;
187 493 : len += 100;
188 493 : pw = xmalloc_secure( len );
189 493 : if( pw2 )
190 : {
191 0 : memcpy(pw, pw2, i );
192 0 : xfree (pw2);
193 : }
194 : else
195 493 : i=0;
196 : }
197 7640 : if (read( fd, pw+i, 1) != 1 || pw[i] == '\n' )
198 : break;
199 7147 : }
200 493 : pw[i] = 0;
201 493 : if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK)
202 0 : tty_printf("\b\b\b \n" );
203 :
204 493 : xfree ( fd_passwd );
205 493 : fd_passwd = pw;
206 : }
207 :
208 :
209 : /*
210 : * Ask the GPG Agent for the passphrase.
211 : * Mode 0: Allow cached passphrase
212 : * 1: No cached passphrase; that is we are asking for a new passphrase
213 : * FIXME: Only partially implemented
214 : *
215 : * Note that TRYAGAIN_TEXT must not be translated. If CANCELED is not
216 : * NULL, the function does set it to 1 if the user canceled the
217 : * operation. If CACHEID is not NULL, it will be used as the cacheID
218 : * for the gpg-agent; if is NULL and a key fingerprint can be
219 : * computed, this will be used as the cacheid.
220 : */
221 : static char *
222 0 : passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
223 : const char *tryagain_text,
224 : const char *custom_description,
225 : const char *custom_prompt, int *canceled)
226 : {
227 : int rc;
228 0 : char *atext = NULL;
229 0 : char *pw = NULL;
230 0 : PKT_public_key *pk = xmalloc_clear( sizeof *pk );
231 : byte fpr[MAX_FINGERPRINT_LEN];
232 0 : int have_fpr = 0;
233 : char *orig_codeset;
234 : char *my_prompt;
235 : char hexfprbuf[20*2+1];
236 : const char *my_cacheid;
237 0 : int check = (mode == 1);
238 :
239 0 : if (canceled)
240 0 : *canceled = 0;
241 :
242 : #if MAX_FINGERPRINT_LEN < 20
243 : #error agent needs a 20 byte fingerprint
244 : #endif
245 :
246 0 : memset (fpr, 0, MAX_FINGERPRINT_LEN );
247 0 : if( keyid && get_pubkey( pk, keyid ) )
248 : {
249 0 : free_public_key (pk);
250 0 : pk = NULL; /* oops: no key for some reason */
251 : }
252 :
253 0 : orig_codeset = i18n_switchto_utf8 ();
254 :
255 0 : if (custom_description)
256 0 : atext = native_to_utf8 (custom_description);
257 0 : else if ( !mode && pk && keyid )
258 0 : {
259 : char *uid;
260 : size_t uidlen;
261 0 : const char *algo_name = openpgp_pk_algo_name ( pk->pubkey_algo );
262 : const char *timestr;
263 : char *maink;
264 :
265 0 : if ( !algo_name )
266 0 : algo_name = "?";
267 :
268 0 : if (keyid[2] && keyid[3]
269 0 : && keyid[0] != keyid[2]
270 0 : && keyid[1] != keyid[3] )
271 0 : maink = xasprintf (_(" (main key ID %s)"), keystr (&keyid[2]));
272 : else
273 0 : maink = xstrdup ("");
274 :
275 0 : uid = get_user_id ( keyid, &uidlen );
276 0 : timestr = strtimestamp (pk->timestamp);
277 :
278 0 : atext = xasprintf (_("Please enter the passphrase to unlock the"
279 : " secret key for the OpenPGP certificate:\n"
280 : "\"%.*s\"\n"
281 : "%u-bit %s key, ID %s,\n"
282 : "created %s%s.\n"),
283 : (int)uidlen, uid,
284 : nbits_from_pk (pk), algo_name, keystr(&keyid[0]),
285 : timestr, maink);
286 0 : xfree (uid);
287 0 : xfree (maink);
288 :
289 : {
290 : size_t dummy;
291 0 : fingerprint_from_pk( pk, fpr, &dummy );
292 0 : have_fpr = 1;
293 : }
294 :
295 : }
296 : else
297 0 : atext = xstrdup ( _("Enter passphrase\n") );
298 :
299 :
300 0 : if (!mode && cacheid)
301 0 : my_cacheid = cacheid;
302 0 : else if (!mode && have_fpr)
303 0 : my_cacheid = bin2hex (fpr, 20, hexfprbuf);
304 : else
305 0 : my_cacheid = NULL;
306 :
307 0 : if (tryagain_text)
308 0 : tryagain_text = _(tryagain_text);
309 :
310 0 : my_prompt = custom_prompt ? native_to_utf8 (custom_prompt): NULL;
311 :
312 0 : rc = agent_get_passphrase (my_cacheid, tryagain_text, my_prompt, atext,
313 : repeat, check, &pw);
314 :
315 0 : xfree (my_prompt);
316 0 : xfree (atext); atext = NULL;
317 :
318 0 : i18n_switchback (orig_codeset);
319 :
320 :
321 0 : if (!rc)
322 : ;
323 0 : else if (gpg_err_code (rc) == GPG_ERR_CANCELED
324 0 : || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
325 : {
326 0 : log_info (_("cancelled by user\n") );
327 0 : if (canceled)
328 0 : *canceled = 1;
329 : }
330 : else
331 : {
332 0 : log_error (_("problem with the agent: %s\n"), gpg_strerror (rc));
333 : /* Due to limitations in the API of the upper layers they
334 : consider an error as no passphrase entered. This works in
335 : most cases but not during key creation where this should
336 : definitely not happen and let it continue without requiring a
337 : passphrase. Given that now all the upper layers handle a
338 : cancel correctly, we simply set the cancel flag now for all
339 : errors from the agent. */
340 0 : if (canceled)
341 0 : *canceled = 1;
342 :
343 0 : write_status_errcode ("get_passphrase", rc);
344 : }
345 :
346 0 : free_public_key (pk);
347 0 : if (rc)
348 : {
349 0 : xfree (pw);
350 0 : return NULL;
351 : }
352 0 : return pw;
353 : }
354 :
355 :
356 : /*
357 : * Clear the cached passphrase. If CACHEID is not NULL, it will be
358 : * used instead of a cache ID derived from KEYID.
359 : */
360 : void
361 0 : passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
362 : {
363 : int rc;
364 :
365 : (void)algo;
366 :
367 0 : if (!cacheid)
368 : {
369 : PKT_public_key *pk;
370 : # if MAX_FINGERPRINT_LEN < 20
371 : # error agent needs a 20 byte fingerprint
372 : # endif
373 : byte fpr[MAX_FINGERPRINT_LEN];
374 : char hexfprbuf[2*20+1];
375 : size_t dummy;
376 :
377 0 : pk = xcalloc (1, sizeof *pk);
378 0 : if ( !keyid || get_pubkey( pk, keyid ) )
379 : {
380 0 : log_error ("key not found in passphrase_clear_cache\n");
381 0 : free_public_key (pk);
382 0 : return;
383 : }
384 0 : memset (fpr, 0, MAX_FINGERPRINT_LEN );
385 0 : fingerprint_from_pk ( pk, fpr, &dummy );
386 0 : bin2hex (fpr, 20, hexfprbuf);
387 0 : rc = agent_clear_passphrase (hexfprbuf);
388 0 : free_public_key ( pk );
389 : }
390 : else
391 0 : rc = agent_clear_passphrase (cacheid);
392 :
393 0 : if (rc)
394 0 : log_error (_("problem with the agent: %s\n"), gpg_strerror (rc));
395 : }
396 :
397 :
398 : /* Return a new DEK object using the string-to-key specifier S2K. Use
399 : KEYID and PUBKEY_ALGO to prompt the user. Returns NULL is the user
400 : selected to cancel the passphrase entry and if CANCELED is not
401 : NULL, sets it to true.
402 :
403 : MODE 0: Allow cached passphrase
404 : 1: Ignore cached passphrase
405 : 2: Ditto, but create a new key
406 : 3: Allow cached passphrase; use the S2K salt as the cache ID
407 : 4: Ditto, but create a new key
408 : */
409 : DEK *
410 436 : passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
411 : int cipher_algo, STRING2KEY *s2k, int mode,
412 : const char *tryagain_text,
413 : const char *custdesc, const char *custprompt,
414 : int *canceled)
415 : {
416 436 : char *pw = NULL;
417 : DEK *dek;
418 : STRING2KEY help_s2k;
419 : int dummy_canceled;
420 436 : char s2k_cacheidbuf[1+16+1], *s2k_cacheid = NULL;
421 :
422 436 : if (!canceled)
423 218 : canceled = &dummy_canceled;
424 436 : *canceled = 0;
425 :
426 436 : if ( !s2k )
427 : {
428 0 : assert (mode != 3 && mode != 4);
429 : /* This is used for the old rfc1991 mode
430 : * Note: This must match the code in encode.c with opt.rfc1991 set */
431 0 : s2k = &help_s2k;
432 0 : s2k->mode = 0;
433 0 : s2k->hash_algo = S2K_DIGEST_ALGO;
434 : }
435 :
436 : /* Create a new salt or what else to be filled into the s2k for a
437 : new key. */
438 436 : if ((mode == 2 || mode == 4) && (s2k->mode == 1 || s2k->mode == 3))
439 : {
440 218 : gcry_randomize (s2k->salt, 8, GCRY_STRONG_RANDOM);
441 218 : if ( s2k->mode == 3 )
442 : {
443 : /* We delay the encoding until it is really needed. This is
444 : if we are going to dynamically calibrate it, we need to
445 : call out to gpg-agent and that should not be done during
446 : option processing in main(). */
447 218 : if (!opt.s2k_count)
448 0 : opt.s2k_count = encode_s2k_iterations (0);
449 218 : s2k->count = opt.s2k_count;
450 : }
451 : }
452 :
453 : /* If we do not have a passphrase available in NEXT_PW and status
454 : information are request, we print them now. */
455 436 : if ( !next_pw && is_status_enabled() )
456 : {
457 : char buf[50];
458 :
459 0 : if ( keyid )
460 : {
461 0 : emit_status_need_passphrase (keyid,
462 0 : keyid[2] && keyid[3]? keyid+2:NULL,
463 : pubkey_algo);
464 : }
465 : else
466 : {
467 0 : snprintf (buf, sizeof buf -1, "%d %d %d",
468 0 : cipher_algo, s2k->mode, s2k->hash_algo );
469 0 : write_status_text ( STATUS_NEED_PASSPHRASE_SYM, buf );
470 : }
471 : }
472 :
473 : /* If we do have a keyID, we do not have a passphrase available in
474 : NEXT_PW, we are not running in batch mode and we do not want to
475 : ignore the passphrase cache (mode!=1), print a prompt with
476 : information on that key. */
477 436 : if ( keyid && !opt.batch && !next_pw && mode!=1 )
478 : {
479 0 : PKT_public_key *pk = xmalloc_clear( sizeof *pk );
480 : char *p;
481 :
482 0 : p = get_user_id_native(keyid);
483 0 : tty_printf ("\n");
484 0 : tty_printf (_("You need a passphrase to unlock the secret key for\n"
485 : "user: \"%s\"\n"),p);
486 0 : xfree(p);
487 :
488 0 : if ( !get_pubkey( pk, keyid ) )
489 : {
490 0 : const char *s = openpgp_pk_algo_name ( pk->pubkey_algo );
491 :
492 0 : tty_printf (_("%u-bit %s key, ID %s, created %s"),
493 : nbits_from_pk( pk ), s?s:"?", keystr(keyid),
494 : strtimestamp(pk->timestamp) );
495 0 : if ( keyid[2] && keyid[3]
496 0 : && keyid[0] != keyid[2] && keyid[1] != keyid[3] )
497 : {
498 0 : if ( keystrlen () > 10 )
499 : {
500 0 : tty_printf ("\n");
501 0 : tty_printf (_(" (subkey on main key ID %s)"),
502 : keystr(&keyid[2]) );
503 : }
504 : else
505 0 : tty_printf ( _(" (main key ID %s)"), keystr(&keyid[2]) );
506 : }
507 0 : tty_printf("\n");
508 : }
509 :
510 0 : tty_printf("\n");
511 0 : free_public_key (pk);
512 : }
513 :
514 436 : if ( next_pw )
515 : {
516 : /* Simply return the passphrase we already have in NEXT_PW. */
517 0 : pw = next_pw;
518 0 : next_pw = NULL;
519 : }
520 436 : else if ( have_static_passphrase () )
521 : {
522 : /* Return the passphrase we have stored in FD_PASSWD. */
523 436 : pw = xmalloc_secure ( strlen(fd_passwd)+1 );
524 436 : strcpy ( pw, fd_passwd );
525 : }
526 : else
527 : {
528 0 : if ((mode == 3 || mode == 4) && (s2k->mode == 1 || s2k->mode == 3))
529 : {
530 0 : memset (s2k_cacheidbuf, 0, sizeof s2k_cacheidbuf);
531 0 : *s2k_cacheidbuf = 'S';
532 0 : bin2hex (s2k->salt, 8, s2k_cacheidbuf + 1);
533 0 : s2k_cacheid = s2k_cacheidbuf;
534 : }
535 :
536 0 : if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
537 : {
538 : char buf[32];
539 :
540 0 : snprintf (buf, sizeof (buf), "%u", 100);
541 0 : write_status_text (STATUS_INQUIRE_MAXLEN, buf);
542 : }
543 :
544 : /* Divert to the gpg-agent. */
545 0 : pw = passphrase_get (keyid, mode == 2, s2k_cacheid,
546 0 : (mode == 2 || mode == 4)? opt.passphrase_repeat : 0,
547 : tryagain_text, custdesc, custprompt, canceled);
548 0 : if (*canceled)
549 : {
550 0 : xfree (pw);
551 0 : write_status( STATUS_MISSING_PASSPHRASE );
552 0 : return NULL;
553 : }
554 : }
555 :
556 436 : if ( !pw || !*pw )
557 0 : write_status( STATUS_MISSING_PASSPHRASE );
558 :
559 : /* Hash the passphrase and store it in a newly allocated DEK object.
560 : Keep a copy of the passphrase in LAST_PW for use by
561 : get_last_passphrase(). */
562 436 : dek = xmalloc_secure_clear ( sizeof *dek );
563 436 : dek->algo = cipher_algo;
564 436 : if ( (!pw || !*pw) && (mode == 2 || mode == 4))
565 0 : dek->keylen = 0;
566 : else
567 : {
568 : gpg_error_t err;
569 :
570 436 : dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo);
571 436 : if (!(dek->keylen > 0 && dek->keylen <= DIM(dek->key)))
572 0 : BUG ();
573 1744 : err = gcry_kdf_derive (pw, strlen (pw),
574 436 : s2k->mode == 3? GCRY_KDF_ITERSALTED_S2K :
575 0 : s2k->mode == 1? GCRY_KDF_SALTED_S2K :
576 : /* */ GCRY_KDF_SIMPLE_S2K,
577 436 : s2k->hash_algo, s2k->salt, 8,
578 436 : S2K_DECODE_COUNT(s2k->count),
579 436 : dek->keylen, dek->key);
580 436 : if (err)
581 : {
582 0 : log_error ("gcry_kdf_derive failed: %s", gpg_strerror (err));
583 0 : xfree (pw);
584 0 : xfree (dek);
585 0 : write_status( STATUS_MISSING_PASSPHRASE );
586 0 : return NULL;
587 : }
588 : }
589 436 : if (s2k_cacheid)
590 0 : memcpy (dek->s2k_cacheid, s2k_cacheid, sizeof dek->s2k_cacheid);
591 436 : xfree(last_pw);
592 436 : last_pw = pw;
593 436 : return dek;
594 : }
595 :
596 :
597 : DEK *
598 436 : passphrase_to_dek (u32 *keyid, int pubkey_algo,
599 : int cipher_algo, STRING2KEY *s2k, int mode,
600 : const char *tryagain_text, int *canceled)
601 : {
602 436 : return passphrase_to_dek_ext (keyid, pubkey_algo, cipher_algo,
603 : s2k, mode, tryagain_text, NULL, NULL,
604 : canceled);
605 : }
606 :
607 :
608 : /* Emit the USERID_HINT and the NEED_PASSPHRASE status messages.
609 : MAINKEYID may be NULL. */
610 : void
611 0 : emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo)
612 : {
613 : char buf[50];
614 : char *us;
615 :
616 0 : us = get_long_user_id_string (keyid);
617 0 : write_status_text (STATUS_USERID_HINT, us);
618 0 : xfree (us);
619 :
620 0 : snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0",
621 0 : (ulong)keyid[0],
622 0 : (ulong)keyid[1],
623 0 : (ulong)(mainkeyid? mainkeyid[0]:keyid[0]),
624 0 : (ulong)(mainkeyid? mainkeyid[1]:keyid[1]),
625 : pubkey_algo);
626 :
627 0 : write_status_text (STATUS_NEED_PASSPHRASE, buf);
628 0 : }
629 :
630 :
631 : /* Return an allocated utf-8 string describing the key PK. If ESCAPED
632 : is true spaces and control characters are percent or plus escaped.
633 : MODE describes the use of the key description; use one of the
634 : FORMAT_KEYDESC_ macros. */
635 : char *
636 386 : gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
637 : {
638 : char *uid;
639 : size_t uidlen;
640 : const char *algo_name;
641 : const char *timestr;
642 : char *orig_codeset;
643 : char *maink;
644 : char *desc;
645 : const char *prompt;
646 386 : const char *trailer = "";
647 : int is_subkey;
648 :
649 1155 : is_subkey = (pk->main_keyid[0] && pk->main_keyid[1]
650 383 : && pk->keyid[0] != pk->main_keyid[0]
651 645 : && pk->keyid[1] != pk->main_keyid[1]);
652 386 : algo_name = openpgp_pk_algo_name (pk->pubkey_algo);
653 386 : timestr = strtimestamp (pk->timestamp);
654 386 : uid = get_user_id (is_subkey? pk->main_keyid:pk->keyid, &uidlen);
655 :
656 386 : orig_codeset = i18n_switchto_utf8 ();
657 :
658 386 : if (is_subkey)
659 259 : maink = xtryasprintf (_(" (main key ID %s)"), keystr (pk->main_keyid));
660 : else
661 127 : maink = NULL;
662 :
663 386 : switch (mode)
664 : {
665 : case FORMAT_KEYDESC_NORMAL:
666 372 : prompt = _("Please enter the passphrase to unlock the"
667 : " OpenPGP secret key:");
668 372 : break;
669 : case FORMAT_KEYDESC_IMPORT:
670 14 : prompt = _("Please enter the passphrase to import the"
671 : " OpenPGP secret key:");
672 14 : break;
673 : case FORMAT_KEYDESC_EXPORT:
674 0 : if (is_subkey)
675 0 : prompt = _("Please enter the passphrase to export the"
676 : " OpenPGP secret subkey:");
677 : else
678 0 : prompt = _("Please enter the passphrase to export the"
679 : " OpenPGP secret key:");
680 0 : break;
681 : case FORMAT_KEYDESC_DELKEY:
682 0 : if (is_subkey)
683 0 : prompt = _("Do you really want to permanently delete the"
684 : " OpenPGP secret subkey key:");
685 : else
686 0 : prompt = _("Do you really want to permanently delete the"
687 : " OpenPGP secret key:");
688 0 : trailer = "?";
689 0 : break;
690 : default:
691 0 : prompt = "?";
692 0 : break;
693 : }
694 :
695 772 : desc = xtryasprintf (_("%s\n"
696 : "\"%.*s\"\n"
697 : "%u-bit %s key, ID %s,\n"
698 : "created %s%s.\n%s"),
699 : prompt,
700 : (int)uidlen, uid,
701 : nbits_from_pk (pk), algo_name,
702 386 : keystr (pk->keyid), timestr,
703 : maink?maink:"", trailer);
704 386 : xfree (maink);
705 386 : xfree (uid);
706 :
707 386 : i18n_switchback (orig_codeset);
708 :
709 386 : if (escaped)
710 : {
711 386 : char *tmp = percent_plus_escape (desc);
712 386 : xfree (desc);
713 386 : desc = tmp;
714 : }
715 :
716 386 : return desc;
717 : }
|