2 * PuTTY key generation front end (Windows).
10 #define PUTTY_DO_GLOBALS
21 #define WM_DONEKEY (WM_APP + 1)
23 #define DEFAULT_KEYSIZE 2048
25 static char *cmdline_keyfile = NULL;
28 * Print a modal (Really Bad) message box and perform a fatal exit.
30 void modalfatalbox(char *fmt, ...)
36 stuff = dupvprintf(fmt, ap);
38 MessageBox(NULL, stuff, "PuTTYgen Fatal Error",
39 MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
45 * Print a non-fatal message box and do not exit.
47 void nonfatal(char *fmt, ...)
53 stuff = dupvprintf(fmt, ap);
55 MessageBox(NULL, stuff, "PuTTYgen Error",
56 MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
60 /* ----------------------------------------------------------------------
61 * Progress report code. This is really horrible :-)
63 #define PROGRESSRANGE 65535
69 unsigned startpoint, total;
70 unsigned param, current, n; /* if exponential */
71 unsigned mult; /* if linear */
73 unsigned total, divisor, range;
77 static void progress_update(void *param, int action, int phase, int iprogress)
79 struct progress *p = (struct progress *) param;
80 unsigned progress = iprogress;
83 if (action < PROGFN_READY && p->nphases < phase)
86 case PROGFN_INITIALISE:
89 case PROGFN_LIN_PHASE:
90 p->phases[phase-1].exponential = 0;
91 p->phases[phase-1].mult = p->phases[phase].total / progress;
93 case PROGFN_EXP_PHASE:
94 p->phases[phase-1].exponential = 1;
95 p->phases[phase-1].param = 0x10000 + progress;
96 p->phases[phase-1].current = p->phases[phase-1].total;
97 p->phases[phase-1].n = 0;
99 case PROGFN_PHASE_EXTENT:
100 p->phases[phase-1].total = progress;
106 for (i = 0; i < p->nphases; i++) {
107 p->phases[i].startpoint = total;
108 total += p->phases[i].total;
111 p->divisor = ((p->total + PROGRESSRANGE - 1) / PROGRESSRANGE);
112 p->range = p->total / p->divisor;
113 SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, p->range));
116 case PROGFN_PROGRESS:
117 if (p->phases[phase-1].exponential) {
118 while (p->phases[phase-1].n < progress) {
119 p->phases[phase-1].n++;
120 p->phases[phase-1].current *= p->phases[phase-1].param;
121 p->phases[phase-1].current /= 0x10000;
123 position = (p->phases[phase-1].startpoint +
124 p->phases[phase-1].total - p->phases[phase-1].current);
126 position = (p->phases[phase-1].startpoint +
127 progress * p->phases[phase-1].mult);
129 SendMessage(p->progbar, PBM_SETPOS, position / p->divisor, 0);
136 struct PassphraseProcStruct {
142 * Dialog-box function for the passphrase box.
144 static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
145 WPARAM wParam, LPARAM lParam)
147 static char **passphrase = NULL;
148 struct PassphraseProcStruct *p;
152 SetForegroundWindow(hwnd);
153 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
154 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
159 { /* centre the window */
163 hw = GetDesktopWindow();
164 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
166 (rs.right + rs.left + rd.left - rd.right) / 2,
167 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
168 rd.right - rd.left, rd.bottom - rd.top, TRUE);
171 p = (struct PassphraseProcStruct *) lParam;
172 passphrase = p->passphrase;
174 SetDlgItemText(hwnd, 101, p->comment);
175 burnstr(*passphrase);
176 *passphrase = dupstr("");
177 SetDlgItemText(hwnd, 102, *passphrase);
180 switch (LOWORD(wParam)) {
190 case 102: /* edit box */
191 if ((HIWORD(wParam) == EN_CHANGE) && passphrase) {
192 burnstr(*passphrase);
193 *passphrase = GetDlgItemText_alloc(hwnd, 102);
206 * Prompt for a key file. Assumes the filename buffer is of size
209 static int prompt_keyfile(HWND hwnd, char *dlgtitle,
210 char *filename, int save, int ppk)
213 memset(&of, 0, sizeof(of));
216 of.lpstrFilter = "PuTTY Private Key Files (*.ppk)\0*.ppk\0"
217 "All Files (*.*)\0*\0\0\0";
218 of.lpstrDefExt = ".ppk";
220 of.lpstrFilter = "All Files (*.*)\0*\0\0\0";
222 of.lpstrCustomFilter = NULL;
224 of.lpstrFile = filename;
226 of.nMaxFile = FILENAME_MAX;
227 of.lpstrFileTitle = NULL;
228 of.lpstrTitle = dlgtitle;
230 return request_file(NULL, &of, FALSE, save);
234 * Dialog-box function for the Licence box.
236 static int CALLBACK LicenceProc(HWND hwnd, UINT msg,
237 WPARAM wParam, LPARAM lParam)
244 { /* centre the window */
248 hw = GetDesktopWindow();
249 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
251 (rs.right + rs.left + rd.left - rd.right) / 2,
252 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
253 rd.right - rd.left, rd.bottom - rd.top, TRUE);
258 switch (LOWORD(wParam)) {
273 * Dialog-box function for the About box.
275 static int CALLBACK AboutProc(HWND hwnd, UINT msg,
276 WPARAM wParam, LPARAM lParam)
283 { /* centre the window */
287 hw = GetDesktopWindow();
288 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
290 (rs.right + rs.left + rd.left - rd.right) / 2,
291 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
292 rd.right - rd.left, rd.bottom - rd.top, TRUE);
295 SetDlgItemText(hwnd, 100, ver);
298 switch (LOWORD(wParam)) {
304 EnableWindow(hwnd, 0);
305 DialogBox(hinst, MAKEINTRESOURCE(214), hwnd, LicenceProc);
306 EnableWindow(hwnd, 1);
307 SetActiveWindow(hwnd);
318 typedef enum {RSA, DSA, ECDSA, ED25519} keytype;
321 * Thread to generate a key.
323 struct rsa_key_thread_params {
324 HWND progressbar; /* notify this with progress */
325 HWND dialog; /* notify this on completion */
326 int keysize; /* bits in key */
330 struct dss_key *dsskey;
331 struct ec_key *eckey;
334 static DWORD WINAPI generate_rsa_key_thread(void *param)
336 struct rsa_key_thread_params *params =
337 (struct rsa_key_thread_params *) param;
338 struct progress prog;
339 prog.progbar = params->progressbar;
341 progress_update(&prog, PROGFN_INITIALISE, 0, 0);
343 if (params->keytype == DSA)
344 dsa_generate(params->dsskey, params->keysize, progress_update, &prog);
345 else if (params->keytype == ECDSA)
346 ec_generate(params->eckey, params->keysize, progress_update, &prog);
347 else if (params->keytype == ED25519)
348 ec_edgenerate(params->eckey, params->keysize, progress_update, &prog);
350 rsa_generate(params->key, params->keysize, progress_update, &prog);
352 PostMessage(params->dialog, WM_DONEKEY, 0, 0);
358 struct MainDlgState {
359 int collecting_entropy;
360 int generation_thread_exists;
362 int entropy_got, entropy_required, entropy_size;
366 char **commentptr; /* points to key.comment or ssh2key.comment */
367 struct ssh2_userkey ssh2key;
371 struct dss_key dsskey;
374 HMENU filemenu, keymenu, cvtmenu;
377 static void hidemany(HWND hwnd, const int *ids, int hideit)
380 ShowWindow(GetDlgItem(hwnd, *ids++), (hideit ? SW_HIDE : SW_SHOW));
384 static void setupbigedit1(HWND hwnd, int id, int idstatic, struct RSAKey *key)
386 char *buffer = ssh1_pubkey_str(key);
387 SetDlgItemText(hwnd, id, buffer);
388 SetDlgItemText(hwnd, idstatic,
389 "&Public key for pasting into authorized_keys file:");
393 static void setupbigedit2(HWND hwnd, int id, int idstatic,
394 struct ssh2_userkey *key)
396 char *buffer = ssh2_pubkey_openssh_str(key);
397 SetDlgItemText(hwnd, id, buffer);
398 SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
399 "OpenSSH authorized_keys file:");
404 * Warn about the obsolescent key file format.
406 void old_keyfile_warning(void)
408 static const char mbtitle[] = "PuTTY Key File Warning";
409 static const char message[] =
410 "You are loading an SSH-2 private key which has an\n"
411 "old version of the file format. This means your key\n"
412 "file is not fully tamperproof. Future versions of\n"
413 "PuTTY may stop supporting this private key format,\n"
414 "so we recommend you convert your key to the new\n"
417 "Once the key is loaded into PuTTYgen, you can perform\n"
418 "this conversion simply by saving it again.";
420 MessageBox(NULL, message, mbtitle, MB_OK);
423 static int save_ssh2_pubkey(char *filename, struct ssh2_userkey *key)
425 unsigned char *pub_blob;
431 pub_blob = key->alg->public_blob(key->data, &pub_len);
433 fp = fopen(filename, "wb");
437 fprintf(fp, "---- BEGIN SSH2 PUBLIC KEY ----\n");
439 fprintf(fp, "Comment: \"");
440 for (p = key->comment; *p; p++) {
441 if (*p == '\\' || *p == '\"')
449 while (i < pub_len) {
451 int n = (pub_len - i < 3 ? pub_len - i : 3);
452 base64_encode_atom(pub_blob + i, n, buf);
456 if (++column >= 16) {
464 fprintf(fp, "---- END SSH2 PUBLIC KEY ----\n");
471 controlidstart = 100,
478 IDC_PKSTATIC, IDC_KEYDISPLAY,
479 IDC_FPSTATIC, IDC_FINGERPRINT,
480 IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
481 IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
482 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT,
484 IDC_GENSTATIC, IDC_GENERATE,
485 IDC_LOADSTATIC, IDC_LOAD,
486 IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
488 IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
489 IDC_KEYSSH2ECDSA, IDC_KEYSSH2ED25519,
490 IDC_BITSSTATIC, IDC_BITS,
494 IDC_EXPORT_OPENSSH_AUTO, IDC_EXPORT_OPENSSH_NEW,
498 static const int nokey_ids[] = { IDC_NOKEY, 0 };
499 static const int generating_ids[] = { IDC_GENERATING, IDC_PROGRESS, 0 };
500 static const int gotkey_ids[] = {
501 IDC_PKSTATIC, IDC_KEYDISPLAY,
502 IDC_FPSTATIC, IDC_FINGERPRINT,
503 IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
504 IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
505 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 0
509 * Small UI helper function to switch the state of the main dialog
510 * by enabling and disabling controls and menu items.
512 void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
518 hidemany(hwnd, nokey_ids, FALSE);
519 hidemany(hwnd, generating_ids, TRUE);
520 hidemany(hwnd, gotkey_ids, TRUE);
521 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
522 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
523 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
524 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
525 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
526 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
527 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
528 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
529 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 1);
530 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
531 EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
532 EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
533 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND);
534 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND);
535 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
536 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_ENABLED|MF_BYCOMMAND);
537 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND);
538 EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
539 MF_ENABLED|MF_BYCOMMAND);
540 EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
541 MF_ENABLED|MF_BYCOMMAND);
542 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
543 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
544 MF_GRAYED|MF_BYCOMMAND);
545 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
546 MF_GRAYED|MF_BYCOMMAND);
547 EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
548 MF_GRAYED|MF_BYCOMMAND);
550 case 1: /* generating key */
551 hidemany(hwnd, nokey_ids, TRUE);
552 hidemany(hwnd, generating_ids, FALSE);
553 hidemany(hwnd, gotkey_ids, TRUE);
554 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0);
555 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0);
556 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
557 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
558 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0);
559 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
560 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0);
561 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 0);
562 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 0);
563 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
564 EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND);
565 EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
566 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND);
567 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_GRAYED|MF_BYCOMMAND);
568 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_GRAYED|MF_BYCOMMAND);
569 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_GRAYED|MF_BYCOMMAND);
570 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND);
571 EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
572 MF_GRAYED|MF_BYCOMMAND);
573 EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
574 MF_GRAYED|MF_BYCOMMAND);
575 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
576 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
577 MF_GRAYED|MF_BYCOMMAND);
578 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
579 MF_GRAYED|MF_BYCOMMAND);
580 EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
581 MF_GRAYED|MF_BYCOMMAND);
584 hidemany(hwnd, nokey_ids, TRUE);
585 hidemany(hwnd, generating_ids, TRUE);
586 hidemany(hwnd, gotkey_ids, FALSE);
587 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
588 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
589 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
590 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
591 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
592 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
593 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
594 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
595 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 1);
596 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
597 EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
598 EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND);
599 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_ENABLED|MF_BYCOMMAND);
600 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND);
601 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
602 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA,MF_ENABLED|MF_BYCOMMAND);
603 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND);
604 EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
605 MF_ENABLED|MF_BYCOMMAND);
606 EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
607 MF_ENABLED|MF_BYCOMMAND);
608 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
610 * Enable export menu items if and only if the key type
611 * supports this kind of export.
613 type = state->ssh2 ? SSH_KEYTYPE_SSH2 : SSH_KEYTYPE_SSH1;
614 #define do_export_menuitem(x,y) \
615 EnableMenuItem(state->cvtmenu, x, MF_BYCOMMAND | \
616 (import_target_type(y)==type?MF_ENABLED:MF_GRAYED))
617 do_export_menuitem(IDC_EXPORT_OPENSSH_AUTO, SSH_KEYTYPE_OPENSSH_AUTO);
618 do_export_menuitem(IDC_EXPORT_OPENSSH_NEW, SSH_KEYTYPE_OPENSSH_NEW);
619 do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM);
620 #undef do_export_menuitem
625 void load_key_file(HWND hwnd, struct MainDlgState *state,
626 Filename *filename, int was_import_cmd)
632 const char *errmsg = NULL;
634 struct RSAKey newkey1;
635 struct ssh2_userkey *newkey2 = NULL;
637 type = realtype = key_type(filename);
638 if (type != SSH_KEYTYPE_SSH1 &&
639 type != SSH_KEYTYPE_SSH2 &&
640 !import_possible(type)) {
641 char *msg = dupprintf("Couldn't load private key (%s)",
642 key_type_to_str(type));
643 message_box(msg, "PuTTYgen Error", MB_OK | MB_ICONERROR,
644 HELPCTXID(errors_cantloadkey));
649 if (type != SSH_KEYTYPE_SSH1 &&
650 type != SSH_KEYTYPE_SSH2) {
652 type = import_target_type(type);
657 if (realtype == SSH_KEYTYPE_SSH1)
658 needs_pass = rsakey_encrypted(filename, &comment);
659 else if (realtype == SSH_KEYTYPE_SSH2)
660 needs_pass = ssh2_userkey_encrypted(filename, &comment);
662 needs_pass = import_encrypted(filename, realtype, &comment);
669 struct PassphraseProcStruct pps;
670 pps.passphrase = &passphrase;
671 pps.comment = comment;
672 dlgret = DialogBoxParam(hinst,
673 MAKEINTRESOURCE(210),
674 NULL, PassphraseProc,
680 assert(passphrase != NULL);
682 passphrase = dupstr("");
683 if (type == SSH_KEYTYPE_SSH1) {
684 if (realtype == type)
685 ret = loadrsakey(filename, &newkey1, passphrase, &errmsg);
687 ret = import_ssh1(filename, realtype, &newkey1,
688 passphrase, &errmsg);
690 if (realtype == type)
691 newkey2 = ssh2_load_userkey(filename, passphrase, &errmsg);
693 newkey2 = import_ssh2(filename, realtype, passphrase, &errmsg);
694 if (newkey2 == SSH2_WRONG_PASSPHRASE)
705 char *msg = dupprintf("Couldn't load private key (%s)", errmsg);
706 message_box(msg, "PuTTYgen Error", MB_OK | MB_ICONERROR,
707 HELPCTXID(errors_cantloadkey));
709 } else if (ret == 1) {
711 * Now update the key controls with all the
715 SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
717 SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
719 if (type == SSH_KEYTYPE_SSH1) {
724 state->commentptr = &state->key.comment;
725 state->key = newkey1;
728 * Set the key fingerprint.
730 savecomment = state->key.comment;
731 state->key.comment = NULL;
732 rsa_fingerprint(buf, sizeof(buf),
734 state->key.comment = savecomment;
736 SetDlgItemText(hwnd, IDC_FINGERPRINT, buf);
738 * Construct a decimal representation
739 * of the key, for pasting into
740 * .ssh/authorized_keys on a Unix box.
742 setupbigedit1(hwnd, IDC_KEYDISPLAY,
743 IDC_PKSTATIC, &state->key);
750 &state->ssh2key.comment;
751 state->ssh2key = *newkey2; /* structure copy */
754 savecomment = state->ssh2key.comment;
755 state->ssh2key.comment = NULL;
756 fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data);
757 state->ssh2key.comment = savecomment;
759 SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
762 setupbigedit2(hwnd, IDC_KEYDISPLAY,
763 IDC_PKSTATIC, &state->ssh2key);
765 SetDlgItemText(hwnd, IDC_COMMENTEDIT,
769 * Finally, hide the progress bar and show
772 ui_set_state(hwnd, state, 2);
773 state->key_exists = TRUE;
776 * If the user has imported a foreign key
777 * using the Load command, let them know.
778 * If they've used the Import command, be
781 if (realtype != type && !was_import_cmd) {
783 sprintf(msg, "Successfully imported foreign key\n"
785 "To use this key with PuTTY, you need to\n"
786 "use the \"Save private key\" command to\n"
787 "save it in PuTTY's own format.",
788 key_type_to_str(realtype));
789 MessageBox(NULL, msg, "PuTTYgen Notice",
790 MB_OK | MB_ICONINFORMATION);
797 * Dialog-box function for the main PuTTYgen dialog box.
799 static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
800 WPARAM wParam, LPARAM lParam)
802 static const char generating_msg[] =
803 "Please wait while a key is generated...";
804 static const char entropy_msg[] =
805 "Please generate some randomness by moving the mouse over the blank area.";
806 struct MainDlgState *state;
811 SetWindowLongPtr(hwnd, GWL_EXSTYLE,
812 GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
816 * If we add a Help button, this is where we destroy it
817 * if the help file isn't present.
820 SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG,
821 (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(200)));
823 state = snew(struct MainDlgState);
824 state->generation_thread_exists = FALSE;
825 state->collecting_entropy = FALSE;
826 state->entropy = NULL;
827 state->key_exists = FALSE;
828 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) state);
834 menu1 = CreateMenu();
835 AppendMenu(menu1, MF_ENABLED, IDC_LOAD, "&Load private key");
836 AppendMenu(menu1, MF_ENABLED, IDC_SAVEPUB, "Save p&ublic key");
837 AppendMenu(menu1, MF_ENABLED, IDC_SAVE, "&Save private key");
838 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
839 AppendMenu(menu1, MF_ENABLED, IDC_QUIT, "E&xit");
840 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&File");
841 state->filemenu = menu1;
843 menu1 = CreateMenu();
844 AppendMenu(menu1, MF_ENABLED, IDC_GENERATE, "&Generate key pair");
845 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
846 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH1, "SSH-&1 key (RSA)");
847 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2RSA, "SSH-2 &RSA key");
848 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2DSA, "SSH-2 &DSA key");
849 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ECDSA, "SSH-2 &ECDSA key");
850 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ED25519, "SSH-2 ED&25519 key");
851 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Key");
852 state->keymenu = menu1;
854 menu1 = CreateMenu();
855 AppendMenu(menu1, MF_ENABLED, IDC_IMPORT, "&Import key");
856 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
857 AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_AUTO,
858 "Export &OpenSSH key");
859 AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_NEW,
860 "Export &OpenSSH key (force new file format)");
861 AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM,
862 "Export &ssh.com key");
863 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1,
865 state->cvtmenu = menu1;
867 menu1 = CreateMenu();
868 AppendMenu(menu1, MF_ENABLED, IDC_ABOUT, "&About");
870 AppendMenu(menu1, MF_ENABLED, IDC_GIVEHELP, "&Help");
871 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Help");
879 { /* centre the window */
883 hw = GetDesktopWindow();
884 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
886 (rs.right + rs.left + rd.left - rd.right) / 2,
887 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
888 rd.right - rd.left, rd.bottom - rd.top, TRUE);
892 struct ctlpos cp, cp2;
894 /* Accelerators used: acglops1rbde */
896 ctlposinit(&cp, hwnd, 4, 4, 4);
897 beginbox(&cp, "Key", IDC_BOX_KEY);
899 statictext(&cp2, "No key.", 1, IDC_NOKEY);
901 statictext(&cp2, "", 1, IDC_GENERATING);
902 progressbar(&cp2, IDC_PROGRESS);
904 "&Public key for pasting into authorized_keys file:",
905 IDC_PKSTATIC, IDC_KEYDISPLAY, 5);
906 SendDlgItemMessage(hwnd, IDC_KEYDISPLAY, EM_SETREADONLY, 1, 0);
907 staticedit(&cp, "Key f&ingerprint:", IDC_FPSTATIC,
908 IDC_FINGERPRINT, 75);
909 SendDlgItemMessage(hwnd, IDC_FINGERPRINT, EM_SETREADONLY, 1,
911 staticedit(&cp, "Key &comment:", IDC_COMMENTSTATIC,
912 IDC_COMMENTEDIT, 75);
913 staticpassedit(&cp, "Key p&assphrase:", IDC_PASSPHRASE1STATIC,
914 IDC_PASSPHRASE1EDIT, 75);
915 staticpassedit(&cp, "C&onfirm passphrase:",
916 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 75);
918 beginbox(&cp, "Actions", IDC_BOX_ACTIONS);
919 staticbtn(&cp, "Generate a public/private key pair",
920 IDC_GENSTATIC, "&Generate", IDC_GENERATE);
921 staticbtn(&cp, "Load an existing private key file",
922 IDC_LOADSTATIC, "&Load", IDC_LOAD);
923 static2btn(&cp, "Save the generated key", IDC_SAVESTATIC,
924 "Save p&ublic key", IDC_SAVEPUB,
925 "&Save private key", IDC_SAVE);
927 beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
928 radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 5,
929 "&RSA", IDC_KEYSSH2RSA,
930 "&DSA", IDC_KEYSSH2DSA,
931 "&ECDSA", IDC_KEYSSH2ECDSA,
932 "ED&25519", IDC_KEYSSH2ED25519,
933 "SSH-&1 (RSA)", IDC_KEYSSH1,
935 staticedit(&cp, "Number of &bits in a generated key:",
936 IDC_BITSSTATIC, IDC_BITS, 20);
939 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ECDSA, IDC_KEYSSH2RSA);
940 CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2ECDSA,
941 IDC_KEYSSH2RSA, MF_BYCOMMAND);
942 SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE);
945 * Initially, hide the progress bar and the key display,
946 * and show the no-key display. Also disable the Save
947 * buttons, because with no key we obviously can't save
950 ui_set_state(hwnd, state, 0);
953 * Load a key file if one was provided on the command line.
955 if (cmdline_keyfile) {
956 Filename *fn = filename_from_str(cmdline_keyfile);
957 load_key_file(hwnd, state, fn, 0);
963 state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
964 if (state->collecting_entropy &&
965 state->entropy && state->entropy_got < state->entropy_required) {
966 state->entropy[state->entropy_got++] = lParam;
967 state->entropy[state->entropy_got++] = GetMessageTime();
968 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS,
969 state->entropy_got, 0);
970 if (state->entropy_got >= state->entropy_required) {
971 struct rsa_key_thread_params *params;
975 * Seed the entropy pool
977 random_add_heavynoise(state->entropy, state->entropy_size);
978 smemclr(state->entropy, state->entropy_size);
979 sfree(state->entropy);
980 state->collecting_entropy = FALSE;
982 SetDlgItemText(hwnd, IDC_GENERATING, generating_msg);
983 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
984 MAKELPARAM(0, PROGRESSRANGE));
985 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
987 params = snew(struct rsa_key_thread_params);
988 params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
989 params->dialog = hwnd;
990 params->keysize = state->keysize;
991 params->keytype = state->keytype;
992 params->key = &state->key;
993 params->dsskey = &state->dsskey;
995 if (!CreateThread(NULL, 0, generate_rsa_key_thread,
996 params, 0, &threadid)) {
997 MessageBox(hwnd, "Out of thread resources",
998 "Key generation error",
999 MB_OK | MB_ICONERROR);
1002 state->generation_thread_exists = TRUE;
1008 switch (LOWORD(wParam)) {
1010 case IDC_KEYSSH2RSA:
1011 case IDC_KEYSSH2DSA:
1012 case IDC_KEYSSH2ECDSA:
1013 case IDC_KEYSSH2ED25519:
1015 state = (struct MainDlgState *)
1016 GetWindowLongPtr(hwnd, GWLP_USERDATA);
1017 if (!IsDlgButtonChecked(hwnd, LOWORD(wParam)))
1018 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA,
1020 CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA,
1021 LOWORD(wParam), MF_BYCOMMAND);
1022 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ECDSA,
1024 CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1,
1026 LOWORD(wParam), MF_BYCOMMAND);
1030 PostMessage(hwnd, WM_CLOSE, 0, 0);
1032 case IDC_COMMENTEDIT:
1033 if (HIWORD(wParam) == EN_CHANGE) {
1034 state = (struct MainDlgState *)
1035 GetWindowLongPtr(hwnd, GWLP_USERDATA);
1036 if (state->key_exists) {
1037 HWND editctl = GetDlgItem(hwnd, IDC_COMMENTEDIT);
1038 int len = GetWindowTextLength(editctl);
1039 if (*state->commentptr)
1040 sfree(*state->commentptr);
1041 *state->commentptr = snewn(len + 1, char);
1042 GetWindowText(editctl, *state->commentptr, len + 1);
1044 setupbigedit2(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
1047 setupbigedit1(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
1054 EnableWindow(hwnd, 0);
1055 DialogBox(hinst, MAKEINTRESOURCE(213), hwnd, AboutProc);
1056 EnableWindow(hwnd, 1);
1057 SetActiveWindow(hwnd);
1060 if (HIWORD(wParam) == BN_CLICKED ||
1061 HIWORD(wParam) == BN_DOUBLECLICKED) {
1062 launch_help(hwnd, WINHELP_CTX_puttygen_general);
1066 if (HIWORD(wParam) != BN_CLICKED &&
1067 HIWORD(wParam) != BN_DOUBLECLICKED)
1070 (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1071 if (!state->generation_thread_exists) {
1073 state->keysize = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE);
1075 state->keysize = DEFAULT_KEYSIZE;
1076 /* If we ever introduce a new key type, check it here! */
1077 state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
1078 state->keytype = RSA;
1079 if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA)) {
1080 state->keytype = DSA;
1081 } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) {
1082 state->keytype = ECDSA;
1083 } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ED25519)) {
1084 state->keytype = ED25519;
1086 if (state->keysize < 256) {
1087 int ret = MessageBox(hwnd,
1088 "PuTTYgen will not generate a key"
1089 " smaller than 256 bits.\n"
1090 "Key length reset to 256. Continue?",
1092 MB_ICONWARNING | MB_OKCANCEL);
1095 state->keysize = 256;
1096 SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
1098 if (state->keytype == ECDSA && !(state->keysize == 256 ||
1099 state->keysize == 384 ||
1100 state->keysize == 521)) {
1101 int ret = MessageBox(hwnd,
1102 "Only 256, 384 and 521 bit elliptic"
1103 " curves are supported.\n"
1104 "Key length reset to 256. Continue?",
1106 MB_ICONWARNING | MB_OKCANCEL);
1109 state->keysize = 256;
1110 SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
1112 if (state->keytype == ED25519 && state->keysize != 256) {
1113 int ret = MessageBox(hwnd,
1114 "Only 256 bit Edwards elliptic"
1115 " curves are supported.\n"
1116 "Key length reset to 256. Continue?",
1118 MB_ICONWARNING | MB_OKCANCEL);
1121 state->keysize = 256;
1122 SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
1124 ui_set_state(hwnd, state, 1);
1125 SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
1126 state->key_exists = FALSE;
1127 state->collecting_entropy = TRUE;
1130 * My brief statistical tests on mouse movements
1131 * suggest that there are about 2.5 bits of
1132 * randomness in the x position, 2.5 in the y
1133 * position, and 1.7 in the message time, making
1134 * 5.7 bits of unpredictability per mouse movement.
1135 * However, other people have told me it's far less
1136 * than that, so I'm going to be stupidly cautious
1137 * and knock that down to a nice round 2. With this
1138 * method, we require two words per mouse movement,
1139 * so with 2 bits per mouse movement we expect 2
1140 * bits every 2 words.
1142 state->entropy_required = (state->keysize / 2) * 2;
1143 state->entropy_got = 0;
1144 state->entropy_size = (state->entropy_required *
1146 state->entropy = snewn(state->entropy_required, unsigned);
1148 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
1149 MAKELPARAM(0, state->entropy_required));
1150 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
1154 case IDC_EXPORT_OPENSSH_AUTO:
1155 case IDC_EXPORT_OPENSSH_NEW:
1156 case IDC_EXPORT_SSHCOM:
1157 if (HIWORD(wParam) != BN_CLICKED)
1160 (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1161 if (state->key_exists) {
1162 char filename[FILENAME_MAX];
1163 char *passphrase, *passphrase2;
1167 realtype = SSH_KEYTYPE_SSH2;
1169 realtype = SSH_KEYTYPE_SSH1;
1171 if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_AUTO)
1172 type = SSH_KEYTYPE_OPENSSH_AUTO;
1173 else if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_NEW)
1174 type = SSH_KEYTYPE_OPENSSH_NEW;
1175 else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM)
1176 type = SSH_KEYTYPE_SSHCOM;
1180 if (type != realtype &&
1181 import_target_type(type) != realtype) {
1183 sprintf(msg, "Cannot export an SSH-%d key in an SSH-%d"
1184 " format", (state->ssh2 ? 2 : 1),
1185 (state->ssh2 ? 1 : 2));
1186 MessageBox(hwnd, msg,
1187 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1191 passphrase = GetDlgItemText_alloc(hwnd, IDC_PASSPHRASE1EDIT);
1192 passphrase2 = GetDlgItemText_alloc(hwnd, IDC_PASSPHRASE2EDIT);
1193 if (strcmp(passphrase, passphrase2)) {
1195 "The two passphrases given do not match.",
1196 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1197 burnstr(passphrase);
1198 burnstr(passphrase2);
1201 burnstr(passphrase2);
1204 ret = MessageBox(hwnd,
1205 "Are you sure you want to save this key\n"
1206 "without a passphrase to protect it?",
1208 MB_YESNO | MB_ICONWARNING);
1210 burnstr(passphrase);
1214 if (prompt_keyfile(hwnd, "Save private key as:",
1215 filename, 1, (type == realtype))) {
1217 FILE *fp = fopen(filename, "r");
1221 buffer = dupprintf("Overwrite existing file\n%s?",
1223 ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
1224 MB_YESNO | MB_ICONWARNING);
1227 burnstr(passphrase);
1233 Filename *fn = filename_from_str(filename);
1234 if (type != realtype)
1235 ret = export_ssh2(fn, type, &state->ssh2key,
1236 *passphrase ? passphrase : NULL);
1238 ret = ssh2_save_userkey(fn, &state->ssh2key,
1239 *passphrase ? passphrase :
1243 Filename *fn = filename_from_str(filename);
1244 if (type != realtype)
1245 ret = export_ssh1(fn, type, &state->key,
1246 *passphrase ? passphrase : NULL);
1248 ret = saversakey(fn, &state->key,
1249 *passphrase ? passphrase : NULL);
1253 MessageBox(hwnd, "Unable to save key file",
1254 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1257 burnstr(passphrase);
1261 if (HIWORD(wParam) != BN_CLICKED)
1264 (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1265 if (state->key_exists) {
1266 char filename[FILENAME_MAX];
1267 if (prompt_keyfile(hwnd, "Save public key as:",
1270 FILE *fp = fopen(filename, "r");
1274 buffer = dupprintf("Overwrite existing file\n%s?",
1276 ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
1277 MB_YESNO | MB_ICONWARNING);
1282 fp = fopen(filename, "w");
1284 MessageBox(hwnd, "Unable to open key file",
1285 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1289 unsigned char *blob;
1290 blob = state->ssh2key.alg->public_blob
1291 (state->ssh2key.data, &bloblen);
1292 ssh2_write_pubkey(fp, state->ssh2key.comment,
1294 SSH_KEYTYPE_SSH2_PUBLIC_RFC4716);
1296 ssh1_write_pubkey(fp, &state->key);
1298 if (fclose(fp) < 0) {
1299 MessageBox(hwnd, "Unable to save key file",
1300 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1308 if (HIWORD(wParam) != BN_CLICKED)
1311 (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1312 if (!state->generation_thread_exists) {
1313 char filename[FILENAME_MAX];
1314 if (prompt_keyfile(hwnd, "Load private key:",
1315 filename, 0, LOWORD(wParam)==IDC_LOAD)) {
1316 Filename *fn = filename_from_str(filename);
1317 load_key_file(hwnd, state, fn, LOWORD(wParam) != IDC_LOAD);
1325 state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1326 state->generation_thread_exists = FALSE;
1327 state->key_exists = TRUE;
1328 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
1329 MAKELPARAM(0, PROGRESSRANGE));
1330 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0);
1332 if (state->keytype == DSA) {
1333 state->ssh2key.data = &state->dsskey;
1334 state->ssh2key.alg = &ssh_dss;
1335 } else if (state->keytype == ECDSA) {
1336 state->ssh2key.data = &state->eckey;
1337 state->ssh2key.alg = state->eckey.signalg;
1338 } else if (state->keytype == ED25519) {
1339 state->ssh2key.data = &state->eckey;
1340 state->ssh2key.alg = &ssh_ecdsa_ed25519;
1342 state->ssh2key.data = &state->key;
1343 state->ssh2key.alg = &ssh_rsa;
1345 state->commentptr = &state->ssh2key.comment;
1347 state->commentptr = &state->key.comment;
1350 * Invent a comment for the key. We'll do this by including
1351 * the date in it. This will be so horrifyingly ugly that
1352 * the user will immediately want to change it, which is
1355 *state->commentptr = snewn(30, char);
1359 if (state->keytype == DSA)
1360 strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", &tm);
1361 else if (state->keytype == ECDSA)
1362 strftime(*state->commentptr, 30, "ecdsa-key-%Y%m%d", &tm);
1363 else if (state->keytype == ED25519)
1364 strftime(*state->commentptr, 30, "ed25519-key-%Y%m%d", &tm);
1366 strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", &tm);
1370 * Now update the key controls with all the key data.
1375 * Blank passphrase, initially. This isn't dangerous,
1376 * because we will warn (Are You Sure?) before allowing
1377 * the user to save an unprotected private key.
1379 SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, "");
1380 SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, "");
1384 SetDlgItemText(hwnd, IDC_COMMENTEDIT, *state->commentptr);
1386 * Set the key fingerprint.
1388 savecomment = *state->commentptr;
1389 *state->commentptr = NULL;
1392 fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data);
1393 SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
1397 rsa_fingerprint(buf, sizeof(buf), &state->key);
1398 SetDlgItemText(hwnd, IDC_FINGERPRINT, buf);
1400 *state->commentptr = savecomment;
1402 * Construct a decimal representation of the key, for
1403 * pasting into .ssh/authorized_keys or
1404 * .ssh/authorized_keys2 on a Unix box.
1407 setupbigedit2(hwnd, IDC_KEYDISPLAY,
1408 IDC_PKSTATIC, &state->ssh2key);
1410 setupbigedit1(hwnd, IDC_KEYDISPLAY,
1411 IDC_PKSTATIC, &state->key);
1415 * Finally, hide the progress bar and show the key data.
1417 ui_set_state(hwnd, state, 2);
1421 int id = ((LPHELPINFO)lParam)->iCtrlId;
1424 case IDC_GENERATING:
1428 topic = WINHELP_CTX_puttygen_generate; break;
1430 case IDC_KEYDISPLAY:
1431 topic = WINHELP_CTX_puttygen_pastekey; break;
1433 case IDC_FINGERPRINT:
1434 topic = WINHELP_CTX_puttygen_fingerprint; break;
1435 case IDC_COMMENTSTATIC:
1436 case IDC_COMMENTEDIT:
1437 topic = WINHELP_CTX_puttygen_comment; break;
1438 case IDC_PASSPHRASE1STATIC:
1439 case IDC_PASSPHRASE1EDIT:
1440 case IDC_PASSPHRASE2STATIC:
1441 case IDC_PASSPHRASE2EDIT:
1442 topic = WINHELP_CTX_puttygen_passphrase; break;
1443 case IDC_LOADSTATIC:
1445 topic = WINHELP_CTX_puttygen_load; break;
1446 case IDC_SAVESTATIC:
1448 topic = WINHELP_CTX_puttygen_savepriv; break;
1450 topic = WINHELP_CTX_puttygen_savepub; break;
1451 case IDC_TYPESTATIC:
1453 case IDC_KEYSSH2RSA:
1454 case IDC_KEYSSH2DSA:
1455 case IDC_KEYSSH2ECDSA:
1456 case IDC_KEYSSH2ED25519:
1457 topic = WINHELP_CTX_puttygen_keytype; break;
1458 case IDC_BITSSTATIC:
1460 topic = WINHELP_CTX_puttygen_bits; break;
1462 case IDC_EXPORT_OPENSSH_AUTO:
1463 case IDC_EXPORT_OPENSSH_NEW:
1464 case IDC_EXPORT_SSHCOM:
1465 topic = WINHELP_CTX_puttygen_conversions; break;
1468 launch_help(hwnd, topic);
1475 state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1484 void cleanup_exit(int code)
1490 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
1496 InitCommonControls();
1501 * See if we can find our Help file.
1505 split_into_argv(cmdline, &argc, &argv, NULL);
1508 if (!strcmp(argv[0], "-pgpfp")) {
1513 * Assume the first argument to be a private key file, and
1514 * attempt to load it.
1516 cmdline_keyfile = argv[0];
1521 ret = DialogBox(hinst, MAKEINTRESOURCE(201), NULL, MainDlgProc) != IDOK;
1524 return ret; /* just in case optimiser complains */