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)
389 dec1 = bignum_decimal(key->exponent);
390 dec2 = bignum_decimal(key->modulus);
391 buffer = dupprintf("%d %s %s %s", bignum_bitcount(key->modulus),
392 dec1, dec2, key->comment);
393 SetDlgItemText(hwnd, id, buffer);
394 SetDlgItemText(hwnd, idstatic,
395 "&Public key for pasting into authorized_keys file:");
401 static void setupbigedit2(HWND hwnd, int id, int idstatic,
402 struct ssh2_userkey *key)
404 unsigned char *pub_blob;
409 pub_blob = key->alg->public_blob(key->data, &pub_len);
410 buffer = snewn(strlen(key->alg->name) + 4 * ((pub_len + 2) / 3) +
411 strlen(key->comment) + 3, char);
412 strcpy(buffer, key->alg->name);
413 p = buffer + strlen(buffer);
416 while (i < pub_len) {
417 int n = (pub_len - i < 3 ? pub_len - i : 3);
418 base64_encode_atom(pub_blob + i, n, p);
423 strcpy(p, key->comment);
424 SetDlgItemText(hwnd, id, buffer);
425 SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
426 "OpenSSH authorized_keys file:");
431 static int save_ssh1_pubkey(char *filename, struct RSAKey *key)
436 fp = fopen(filename, "wb");
439 dec1 = bignum_decimal(key->exponent);
440 dec2 = bignum_decimal(key->modulus);
441 fprintf(fp, "%d %s %s %s\n",
442 bignum_bitcount(key->modulus), dec1, dec2, key->comment);
450 * Warn about the obsolescent key file format.
452 void old_keyfile_warning(void)
454 static const char mbtitle[] = "PuTTY Key File Warning";
455 static const char message[] =
456 "You are loading an SSH-2 private key which has an\n"
457 "old version of the file format. This means your key\n"
458 "file is not fully tamperproof. Future versions of\n"
459 "PuTTY may stop supporting this private key format,\n"
460 "so we recommend you convert your key to the new\n"
463 "Once the key is loaded into PuTTYgen, you can perform\n"
464 "this conversion simply by saving it again.";
466 MessageBox(NULL, message, mbtitle, MB_OK);
469 static int save_ssh2_pubkey(char *filename, struct ssh2_userkey *key)
471 unsigned char *pub_blob;
477 pub_blob = key->alg->public_blob(key->data, &pub_len);
479 fp = fopen(filename, "wb");
483 fprintf(fp, "---- BEGIN SSH2 PUBLIC KEY ----\n");
485 fprintf(fp, "Comment: \"");
486 for (p = key->comment; *p; p++) {
487 if (*p == '\\' || *p == '\"')
495 while (i < pub_len) {
497 int n = (pub_len - i < 3 ? pub_len - i : 3);
498 base64_encode_atom(pub_blob + i, n, buf);
502 if (++column >= 16) {
510 fprintf(fp, "---- END SSH2 PUBLIC KEY ----\n");
517 controlidstart = 100,
524 IDC_PKSTATIC, IDC_KEYDISPLAY,
525 IDC_FPSTATIC, IDC_FINGERPRINT,
526 IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
527 IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
528 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT,
530 IDC_GENSTATIC, IDC_GENERATE,
531 IDC_LOADSTATIC, IDC_LOAD,
532 IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
534 IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
535 IDC_KEYSSH2ECDSA, IDC_KEYSSH2ED25519,
536 IDC_BITSSTATIC, IDC_BITS,
540 IDC_EXPORT_OPENSSH_PEM, IDC_EXPORT_OPENSSH_NEW,
544 static const int nokey_ids[] = { IDC_NOKEY, 0 };
545 static const int generating_ids[] = { IDC_GENERATING, IDC_PROGRESS, 0 };
546 static const int gotkey_ids[] = {
547 IDC_PKSTATIC, IDC_KEYDISPLAY,
548 IDC_FPSTATIC, IDC_FINGERPRINT,
549 IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
550 IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
551 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 0
555 * Small UI helper function to switch the state of the main dialog
556 * by enabling and disabling controls and menu items.
558 void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
564 hidemany(hwnd, nokey_ids, FALSE);
565 hidemany(hwnd, generating_ids, TRUE);
566 hidemany(hwnd, gotkey_ids, TRUE);
567 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
568 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
569 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
570 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
571 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
572 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
573 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
574 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
575 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 1);
576 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
577 EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
578 EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
579 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND);
580 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND);
581 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
582 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_ENABLED|MF_BYCOMMAND);
583 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND);
584 EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
585 MF_ENABLED|MF_BYCOMMAND);
586 EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
587 MF_ENABLED|MF_BYCOMMAND);
588 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
589 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_PEM,
590 MF_GRAYED|MF_BYCOMMAND);
591 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
592 MF_GRAYED|MF_BYCOMMAND);
593 EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
594 MF_GRAYED|MF_BYCOMMAND);
596 case 1: /* generating key */
597 hidemany(hwnd, nokey_ids, TRUE);
598 hidemany(hwnd, generating_ids, FALSE);
599 hidemany(hwnd, gotkey_ids, TRUE);
600 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0);
601 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0);
602 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
603 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
604 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0);
605 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
606 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0);
607 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 0);
608 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 0);
609 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
610 EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND);
611 EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
612 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND);
613 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_GRAYED|MF_BYCOMMAND);
614 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_GRAYED|MF_BYCOMMAND);
615 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_GRAYED|MF_BYCOMMAND);
616 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND);
617 EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
618 MF_GRAYED|MF_BYCOMMAND);
619 EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
620 MF_GRAYED|MF_BYCOMMAND);
621 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
622 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_PEM,
623 MF_GRAYED|MF_BYCOMMAND);
624 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
625 MF_GRAYED|MF_BYCOMMAND);
626 EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
627 MF_GRAYED|MF_BYCOMMAND);
630 hidemany(hwnd, nokey_ids, TRUE);
631 hidemany(hwnd, generating_ids, TRUE);
632 hidemany(hwnd, gotkey_ids, FALSE);
633 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
634 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
635 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
636 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
637 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
638 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
639 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
640 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
641 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 1);
642 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
643 EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
644 EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND);
645 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_ENABLED|MF_BYCOMMAND);
646 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND);
647 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
648 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA,MF_ENABLED|MF_BYCOMMAND);
649 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND);
650 EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
651 MF_ENABLED|MF_BYCOMMAND);
652 EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
653 MF_ENABLED|MF_BYCOMMAND);
654 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
656 * Enable export menu items if and only if the key type
657 * supports this kind of export.
659 type = state->ssh2 ? SSH_KEYTYPE_SSH2 : SSH_KEYTYPE_SSH1;
660 #define do_export_menuitem(x,y) \
661 EnableMenuItem(state->cvtmenu, x, MF_BYCOMMAND | \
662 (import_target_type(y)==type?MF_ENABLED:MF_GRAYED))
663 do_export_menuitem(IDC_EXPORT_OPENSSH_PEM, SSH_KEYTYPE_OPENSSH_PEM);
664 do_export_menuitem(IDC_EXPORT_OPENSSH_NEW, SSH_KEYTYPE_OPENSSH_NEW);
665 do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM);
666 #undef do_export_menuitem
671 void load_key_file(HWND hwnd, struct MainDlgState *state,
672 Filename *filename, int was_import_cmd)
678 const char *errmsg = NULL;
680 struct RSAKey newkey1;
681 struct ssh2_userkey *newkey2 = NULL;
683 type = realtype = key_type(filename);
684 if (type != SSH_KEYTYPE_SSH1 &&
685 type != SSH_KEYTYPE_SSH2 &&
686 !import_possible(type)) {
687 char *msg = dupprintf("Couldn't load private key (%s)",
688 key_type_to_str(type));
689 message_box(msg, "PuTTYgen Error", MB_OK | MB_ICONERROR,
690 HELPCTXID(errors_cantloadkey));
695 if (type != SSH_KEYTYPE_SSH1 &&
696 type != SSH_KEYTYPE_SSH2) {
698 type = import_target_type(type);
703 if (realtype == SSH_KEYTYPE_SSH1)
704 needs_pass = rsakey_encrypted(filename, &comment);
705 else if (realtype == SSH_KEYTYPE_SSH2)
706 needs_pass = ssh2_userkey_encrypted(filename, &comment);
708 needs_pass = import_encrypted(filename, realtype, &comment);
715 struct PassphraseProcStruct pps;
716 pps.passphrase = &passphrase;
717 pps.comment = comment;
718 dlgret = DialogBoxParam(hinst,
719 MAKEINTRESOURCE(210),
720 NULL, PassphraseProc,
726 assert(passphrase != NULL);
728 passphrase = dupstr("");
729 if (type == SSH_KEYTYPE_SSH1) {
730 if (realtype == type)
731 ret = loadrsakey(filename, &newkey1, passphrase, &errmsg);
733 ret = import_ssh1(filename, realtype, &newkey1,
734 passphrase, &errmsg);
736 if (realtype == type)
737 newkey2 = ssh2_load_userkey(filename, passphrase, &errmsg);
739 newkey2 = import_ssh2(filename, realtype, passphrase, &errmsg);
740 if (newkey2 == SSH2_WRONG_PASSPHRASE)
751 char *msg = dupprintf("Couldn't load private key (%s)", errmsg);
752 message_box(msg, "PuTTYgen Error", MB_OK | MB_ICONERROR,
753 HELPCTXID(errors_cantloadkey));
755 } else if (ret == 1) {
757 * Now update the key controls with all the
761 SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
763 SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
765 if (type == SSH_KEYTYPE_SSH1) {
770 state->commentptr = &state->key.comment;
771 state->key = newkey1;
774 * Set the key fingerprint.
776 savecomment = state->key.comment;
777 state->key.comment = NULL;
778 rsa_fingerprint(buf, sizeof(buf),
780 state->key.comment = savecomment;
782 SetDlgItemText(hwnd, IDC_FINGERPRINT, buf);
784 * Construct a decimal representation
785 * of the key, for pasting into
786 * .ssh/authorized_keys on a Unix box.
788 setupbigedit1(hwnd, IDC_KEYDISPLAY,
789 IDC_PKSTATIC, &state->key);
796 &state->ssh2key.comment;
797 state->ssh2key = *newkey2; /* structure copy */
800 savecomment = state->ssh2key.comment;
801 state->ssh2key.comment = NULL;
804 fingerprint(state->ssh2key.data);
805 state->ssh2key.comment = savecomment;
807 SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
810 setupbigedit2(hwnd, IDC_KEYDISPLAY,
811 IDC_PKSTATIC, &state->ssh2key);
813 SetDlgItemText(hwnd, IDC_COMMENTEDIT,
817 * Finally, hide the progress bar and show
820 ui_set_state(hwnd, state, 2);
821 state->key_exists = TRUE;
824 * If the user has imported a foreign key
825 * using the Load command, let them know.
826 * If they've used the Import command, be
829 if (realtype != type && !was_import_cmd) {
831 sprintf(msg, "Successfully imported foreign key\n"
833 "To use this key with PuTTY, you need to\n"
834 "use the \"Save private key\" command to\n"
835 "save it in PuTTY's own format.",
836 key_type_to_str(realtype));
837 MessageBox(NULL, msg, "PuTTYgen Notice",
838 MB_OK | MB_ICONINFORMATION);
845 * Dialog-box function for the main PuTTYgen dialog box.
847 static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
848 WPARAM wParam, LPARAM lParam)
850 static const char generating_msg[] =
851 "Please wait while a key is generated...";
852 static const char entropy_msg[] =
853 "Please generate some randomness by moving the mouse over the blank area.";
854 struct MainDlgState *state;
859 SetWindowLongPtr(hwnd, GWL_EXSTYLE,
860 GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
864 * If we add a Help button, this is where we destroy it
865 * if the help file isn't present.
868 SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG,
869 (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(200)));
871 state = snew(struct MainDlgState);
872 state->generation_thread_exists = FALSE;
873 state->collecting_entropy = FALSE;
874 state->entropy = NULL;
875 state->key_exists = FALSE;
876 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) state);
882 menu1 = CreateMenu();
883 AppendMenu(menu1, MF_ENABLED, IDC_LOAD, "&Load private key");
884 AppendMenu(menu1, MF_ENABLED, IDC_SAVEPUB, "Save p&ublic key");
885 AppendMenu(menu1, MF_ENABLED, IDC_SAVE, "&Save private key");
886 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
887 AppendMenu(menu1, MF_ENABLED, IDC_QUIT, "E&xit");
888 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&File");
889 state->filemenu = menu1;
891 menu1 = CreateMenu();
892 AppendMenu(menu1, MF_ENABLED, IDC_GENERATE, "&Generate key pair");
893 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
894 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH1, "SSH-&1 key (RSA)");
895 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2RSA, "SSH-2 &RSA key");
896 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2DSA, "SSH-2 &DSA key");
897 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ECDSA, "SSH-2 &ECDSA key");
898 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ED25519, "SSH-2 ED&25519 key");
899 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Key");
900 state->keymenu = menu1;
902 menu1 = CreateMenu();
903 AppendMenu(menu1, MF_ENABLED, IDC_IMPORT, "&Import key");
904 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
905 AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_PEM,
906 "Export &OpenSSH key (old PEM format)");
907 AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_NEW,
908 "Export &OpenSSH key (new format)");
909 AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM,
910 "Export &ssh.com key");
911 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1,
913 state->cvtmenu = menu1;
915 menu1 = CreateMenu();
916 AppendMenu(menu1, MF_ENABLED, IDC_ABOUT, "&About");
918 AppendMenu(menu1, MF_ENABLED, IDC_GIVEHELP, "&Help");
919 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Help");
927 { /* centre the window */
931 hw = GetDesktopWindow();
932 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
934 (rs.right + rs.left + rd.left - rd.right) / 2,
935 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
936 rd.right - rd.left, rd.bottom - rd.top, TRUE);
940 struct ctlpos cp, cp2;
942 /* Accelerators used: acglops1rbde */
944 ctlposinit(&cp, hwnd, 4, 4, 4);
945 beginbox(&cp, "Key", IDC_BOX_KEY);
947 statictext(&cp2, "No key.", 1, IDC_NOKEY);
949 statictext(&cp2, "", 1, IDC_GENERATING);
950 progressbar(&cp2, IDC_PROGRESS);
952 "&Public key for pasting into authorized_keys file:",
953 IDC_PKSTATIC, IDC_KEYDISPLAY, 5);
954 SendDlgItemMessage(hwnd, IDC_KEYDISPLAY, EM_SETREADONLY, 1, 0);
955 staticedit(&cp, "Key f&ingerprint:", IDC_FPSTATIC,
956 IDC_FINGERPRINT, 75);
957 SendDlgItemMessage(hwnd, IDC_FINGERPRINT, EM_SETREADONLY, 1,
959 staticedit(&cp, "Key &comment:", IDC_COMMENTSTATIC,
960 IDC_COMMENTEDIT, 75);
961 staticpassedit(&cp, "Key p&assphrase:", IDC_PASSPHRASE1STATIC,
962 IDC_PASSPHRASE1EDIT, 75);
963 staticpassedit(&cp, "C&onfirm passphrase:",
964 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 75);
966 beginbox(&cp, "Actions", IDC_BOX_ACTIONS);
967 staticbtn(&cp, "Generate a public/private key pair",
968 IDC_GENSTATIC, "&Generate", IDC_GENERATE);
969 staticbtn(&cp, "Load an existing private key file",
970 IDC_LOADSTATIC, "&Load", IDC_LOAD);
971 static2btn(&cp, "Save the generated key", IDC_SAVESTATIC,
972 "Save p&ublic key", IDC_SAVEPUB,
973 "&Save private key", IDC_SAVE);
975 beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
976 radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 4,
977 "SSH-&1 (RSA)", IDC_KEYSSH1,
978 "SSH-2 &RSA", IDC_KEYSSH2RSA,
979 "SSH-2 &DSA", IDC_KEYSSH2DSA,
980 "SSH-2 &ECDSA", IDC_KEYSSH2ECDSA,
981 "SSH-2 ED&25519", IDC_KEYSSH2ED25519, NULL);
982 staticedit(&cp, "Number of &bits in a generated key:",
983 IDC_BITSSTATIC, IDC_BITS, 20);
986 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ECDSA, IDC_KEYSSH2RSA);
987 CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2ECDSA,
988 IDC_KEYSSH2RSA, MF_BYCOMMAND);
989 SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE);
992 * Initially, hide the progress bar and the key display,
993 * and show the no-key display. Also disable the Save
994 * buttons, because with no key we obviously can't save
997 ui_set_state(hwnd, state, 0);
1000 * Load a key file if one was provided on the command line.
1002 if (cmdline_keyfile) {
1003 Filename *fn = filename_from_str(cmdline_keyfile);
1004 load_key_file(hwnd, state, fn, 0);
1010 state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1011 if (state->collecting_entropy &&
1012 state->entropy && state->entropy_got < state->entropy_required) {
1013 state->entropy[state->entropy_got++] = lParam;
1014 state->entropy[state->entropy_got++] = GetMessageTime();
1015 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS,
1016 state->entropy_got, 0);
1017 if (state->entropy_got >= state->entropy_required) {
1018 struct rsa_key_thread_params *params;
1022 * Seed the entropy pool
1024 random_add_heavynoise(state->entropy, state->entropy_size);
1025 smemclr(state->entropy, state->entropy_size);
1026 sfree(state->entropy);
1027 state->collecting_entropy = FALSE;
1029 SetDlgItemText(hwnd, IDC_GENERATING, generating_msg);
1030 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
1031 MAKELPARAM(0, PROGRESSRANGE));
1032 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
1034 params = snew(struct rsa_key_thread_params);
1035 params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
1036 params->dialog = hwnd;
1037 params->keysize = state->keysize;
1038 params->keytype = state->keytype;
1039 params->key = &state->key;
1040 params->dsskey = &state->dsskey;
1042 if (!CreateThread(NULL, 0, generate_rsa_key_thread,
1043 params, 0, &threadid)) {
1044 MessageBox(hwnd, "Out of thread resources",
1045 "Key generation error",
1046 MB_OK | MB_ICONERROR);
1049 state->generation_thread_exists = TRUE;
1055 switch (LOWORD(wParam)) {
1057 case IDC_KEYSSH2RSA:
1058 case IDC_KEYSSH2DSA:
1059 case IDC_KEYSSH2ECDSA:
1060 case IDC_KEYSSH2ED25519:
1062 state = (struct MainDlgState *)
1063 GetWindowLongPtr(hwnd, GWLP_USERDATA);
1064 if (!IsDlgButtonChecked(hwnd, LOWORD(wParam)))
1065 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA,
1067 CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA,
1068 LOWORD(wParam), MF_BYCOMMAND);
1069 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ECDSA,
1071 CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1,
1073 LOWORD(wParam), MF_BYCOMMAND);
1077 PostMessage(hwnd, WM_CLOSE, 0, 0);
1079 case IDC_COMMENTEDIT:
1080 if (HIWORD(wParam) == EN_CHANGE) {
1081 state = (struct MainDlgState *)
1082 GetWindowLongPtr(hwnd, GWLP_USERDATA);
1083 if (state->key_exists) {
1084 HWND editctl = GetDlgItem(hwnd, IDC_COMMENTEDIT);
1085 int len = GetWindowTextLength(editctl);
1086 if (*state->commentptr)
1087 sfree(*state->commentptr);
1088 *state->commentptr = snewn(len + 1, char);
1089 GetWindowText(editctl, *state->commentptr, len + 1);
1091 setupbigedit2(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
1094 setupbigedit1(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
1101 EnableWindow(hwnd, 0);
1102 DialogBox(hinst, MAKEINTRESOURCE(213), hwnd, AboutProc);
1103 EnableWindow(hwnd, 1);
1104 SetActiveWindow(hwnd);
1107 if (HIWORD(wParam) == BN_CLICKED ||
1108 HIWORD(wParam) == BN_DOUBLECLICKED) {
1109 launch_help(hwnd, WINHELP_CTX_puttygen_general);
1113 if (HIWORD(wParam) != BN_CLICKED &&
1114 HIWORD(wParam) != BN_DOUBLECLICKED)
1117 (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1118 if (!state->generation_thread_exists) {
1120 state->keysize = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE);
1122 state->keysize = DEFAULT_KEYSIZE;
1123 /* If we ever introduce a new key type, check it here! */
1124 state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
1125 state->keytype = RSA;
1126 if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA)) {
1127 state->keytype = DSA;
1128 } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) {
1129 state->keytype = ECDSA;
1130 } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ED25519)) {
1131 state->keytype = ED25519;
1133 if (state->keysize < 256) {
1134 int ret = MessageBox(hwnd,
1135 "PuTTYgen will not generate a key"
1136 " smaller than 256 bits.\n"
1137 "Key length reset to 256. Continue?",
1139 MB_ICONWARNING | MB_OKCANCEL);
1142 state->keysize = 256;
1143 SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
1145 if (state->keytype == ECDSA && !(state->keysize == 256 ||
1146 state->keysize == 384 ||
1147 state->keysize == 521)) {
1148 int ret = MessageBox(hwnd,
1149 "Only 256, 384 and 521 bit elliptic"
1150 " curves are supported.\n"
1151 "Key length reset to 256. Continue?",
1153 MB_ICONWARNING | MB_OKCANCEL);
1156 state->keysize = 256;
1157 SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
1159 if (state->keytype == ED25519 && state->keysize != 256) {
1160 int ret = MessageBox(hwnd,
1161 "Only 256 bit Edwards elliptic"
1162 " curves are supported.\n"
1163 "Key length reset to 256. Continue?",
1165 MB_ICONWARNING | MB_OKCANCEL);
1168 state->keysize = 256;
1169 SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
1171 ui_set_state(hwnd, state, 1);
1172 SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
1173 state->key_exists = FALSE;
1174 state->collecting_entropy = TRUE;
1177 * My brief statistical tests on mouse movements
1178 * suggest that there are about 2.5 bits of
1179 * randomness in the x position, 2.5 in the y
1180 * position, and 1.7 in the message time, making
1181 * 5.7 bits of unpredictability per mouse movement.
1182 * However, other people have told me it's far less
1183 * than that, so I'm going to be stupidly cautious
1184 * and knock that down to a nice round 2. With this
1185 * method, we require two words per mouse movement,
1186 * so with 2 bits per mouse movement we expect 2
1187 * bits every 2 words.
1189 state->entropy_required = (state->keysize / 2) * 2;
1190 state->entropy_got = 0;
1191 state->entropy_size = (state->entropy_required *
1193 state->entropy = snewn(state->entropy_required, unsigned);
1195 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
1196 MAKELPARAM(0, state->entropy_required));
1197 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
1201 case IDC_EXPORT_OPENSSH_PEM:
1202 case IDC_EXPORT_OPENSSH_NEW:
1203 case IDC_EXPORT_SSHCOM:
1204 if (HIWORD(wParam) != BN_CLICKED)
1207 (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1208 if (state->key_exists) {
1209 char filename[FILENAME_MAX];
1210 char *passphrase, *passphrase2;
1214 realtype = SSH_KEYTYPE_SSH2;
1216 realtype = SSH_KEYTYPE_SSH1;
1218 if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_PEM)
1219 type = SSH_KEYTYPE_OPENSSH_PEM;
1220 else if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_NEW)
1221 type = SSH_KEYTYPE_OPENSSH_NEW;
1222 else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM)
1223 type = SSH_KEYTYPE_SSHCOM;
1227 if (type != realtype &&
1228 import_target_type(type) != realtype) {
1230 sprintf(msg, "Cannot export an SSH-%d key in an SSH-%d"
1231 " format", (state->ssh2 ? 2 : 1),
1232 (state->ssh2 ? 1 : 2));
1233 MessageBox(hwnd, msg,
1234 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1238 passphrase = GetDlgItemText_alloc(hwnd, IDC_PASSPHRASE1EDIT);
1239 passphrase2 = GetDlgItemText_alloc(hwnd, IDC_PASSPHRASE2EDIT);
1240 if (strcmp(passphrase, passphrase2)) {
1242 "The two passphrases given do not match.",
1243 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1244 burnstr(passphrase);
1245 burnstr(passphrase2);
1248 burnstr(passphrase2);
1251 ret = MessageBox(hwnd,
1252 "Are you sure you want to save this key\n"
1253 "without a passphrase to protect it?",
1255 MB_YESNO | MB_ICONWARNING);
1257 burnstr(passphrase);
1261 if (prompt_keyfile(hwnd, "Save private key as:",
1262 filename, 1, (type == realtype))) {
1264 FILE *fp = fopen(filename, "r");
1268 buffer = dupprintf("Overwrite existing file\n%s?",
1270 ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
1271 MB_YESNO | MB_ICONWARNING);
1274 burnstr(passphrase);
1280 Filename *fn = filename_from_str(filename);
1281 if (type != realtype)
1282 ret = export_ssh2(fn, type, &state->ssh2key,
1283 *passphrase ? passphrase : NULL);
1285 ret = ssh2_save_userkey(fn, &state->ssh2key,
1286 *passphrase ? passphrase :
1290 Filename *fn = filename_from_str(filename);
1291 if (type != realtype)
1292 ret = export_ssh1(fn, type, &state->key,
1293 *passphrase ? passphrase : NULL);
1295 ret = saversakey(fn, &state->key,
1296 *passphrase ? passphrase : NULL);
1300 MessageBox(hwnd, "Unable to save key file",
1301 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1304 burnstr(passphrase);
1308 if (HIWORD(wParam) != BN_CLICKED)
1311 (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1312 if (state->key_exists) {
1313 char filename[FILENAME_MAX];
1314 if (prompt_keyfile(hwnd, "Save public key as:",
1317 FILE *fp = fopen(filename, "r");
1321 buffer = dupprintf("Overwrite existing file\n%s?",
1323 ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
1324 MB_YESNO | MB_ICONWARNING);
1330 ret = save_ssh2_pubkey(filename, &state->ssh2key);
1332 ret = save_ssh1_pubkey(filename, &state->key);
1335 MessageBox(hwnd, "Unable to save key file",
1336 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1343 if (HIWORD(wParam) != BN_CLICKED)
1346 (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1347 if (!state->generation_thread_exists) {
1348 char filename[FILENAME_MAX];
1349 if (prompt_keyfile(hwnd, "Load private key:",
1350 filename, 0, LOWORD(wParam)==IDC_LOAD)) {
1351 Filename *fn = filename_from_str(filename);
1352 load_key_file(hwnd, state, fn, LOWORD(wParam) != IDC_LOAD);
1360 state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1361 state->generation_thread_exists = FALSE;
1362 state->key_exists = TRUE;
1363 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
1364 MAKELPARAM(0, PROGRESSRANGE));
1365 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0);
1367 if (state->keytype == DSA) {
1368 state->ssh2key.data = &state->dsskey;
1369 state->ssh2key.alg = &ssh_dss;
1370 } else if (state->keytype == ECDSA) {
1371 state->ssh2key.data = &state->eckey;
1372 if (state->eckey.publicKey.curve->fieldBits == 256)
1373 state->ssh2key.alg = &ssh_ecdsa_nistp256;
1374 else if (state->eckey.publicKey.curve->fieldBits == 384)
1375 state->ssh2key.alg = &ssh_ecdsa_nistp384;
1377 state->ssh2key.alg = &ssh_ecdsa_nistp521;
1378 } else if (state->keytype == ED25519) {
1379 state->ssh2key.data = &state->eckey;
1380 state->ssh2key.alg = &ssh_ecdsa_ed25519;
1382 state->ssh2key.data = &state->key;
1383 state->ssh2key.alg = &ssh_rsa;
1385 state->commentptr = &state->ssh2key.comment;
1387 state->commentptr = &state->key.comment;
1390 * Invent a comment for the key. We'll do this by including
1391 * the date in it. This will be so horrifyingly ugly that
1392 * the user will immediately want to change it, which is
1395 *state->commentptr = snewn(30, char);
1399 if (state->keytype == DSA)
1400 strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", &tm);
1401 else if (state->keytype == ECDSA)
1402 strftime(*state->commentptr, 30, "ecdsa-key-%Y%m%d", &tm);
1403 else if (state->keytype == ED25519)
1404 strftime(*state->commentptr, 30, "ed25519-key-%Y%m%d", &tm);
1406 strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", &tm);
1410 * Now update the key controls with all the key data.
1415 * Blank passphrase, initially. This isn't dangerous,
1416 * because we will warn (Are You Sure?) before allowing
1417 * the user to save an unprotected private key.
1419 SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, "");
1420 SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, "");
1424 SetDlgItemText(hwnd, IDC_COMMENTEDIT, *state->commentptr);
1426 * Set the key fingerprint.
1428 savecomment = *state->commentptr;
1429 *state->commentptr = NULL;
1432 fp = state->ssh2key.alg->fingerprint(state->ssh2key.data);
1433 SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
1437 rsa_fingerprint(buf, sizeof(buf), &state->key);
1438 SetDlgItemText(hwnd, IDC_FINGERPRINT, buf);
1440 *state->commentptr = savecomment;
1442 * Construct a decimal representation of the key, for
1443 * pasting into .ssh/authorized_keys or
1444 * .ssh/authorized_keys2 on a Unix box.
1447 setupbigedit2(hwnd, IDC_KEYDISPLAY,
1448 IDC_PKSTATIC, &state->ssh2key);
1450 setupbigedit1(hwnd, IDC_KEYDISPLAY,
1451 IDC_PKSTATIC, &state->key);
1455 * Finally, hide the progress bar and show the key data.
1457 ui_set_state(hwnd, state, 2);
1461 int id = ((LPHELPINFO)lParam)->iCtrlId;
1464 case IDC_GENERATING:
1468 topic = WINHELP_CTX_puttygen_generate; break;
1470 case IDC_KEYDISPLAY:
1471 topic = WINHELP_CTX_puttygen_pastekey; break;
1473 case IDC_FINGERPRINT:
1474 topic = WINHELP_CTX_puttygen_fingerprint; break;
1475 case IDC_COMMENTSTATIC:
1476 case IDC_COMMENTEDIT:
1477 topic = WINHELP_CTX_puttygen_comment; break;
1478 case IDC_PASSPHRASE1STATIC:
1479 case IDC_PASSPHRASE1EDIT:
1480 case IDC_PASSPHRASE2STATIC:
1481 case IDC_PASSPHRASE2EDIT:
1482 topic = WINHELP_CTX_puttygen_passphrase; break;
1483 case IDC_LOADSTATIC:
1485 topic = WINHELP_CTX_puttygen_load; break;
1486 case IDC_SAVESTATIC:
1488 topic = WINHELP_CTX_puttygen_savepriv; break;
1490 topic = WINHELP_CTX_puttygen_savepub; break;
1491 case IDC_TYPESTATIC:
1493 case IDC_KEYSSH2RSA:
1494 case IDC_KEYSSH2DSA:
1495 case IDC_KEYSSH2ECDSA:
1496 case IDC_KEYSSH2ED25519:
1497 topic = WINHELP_CTX_puttygen_keytype; break;
1498 case IDC_BITSSTATIC:
1500 topic = WINHELP_CTX_puttygen_bits; break;
1502 case IDC_EXPORT_OPENSSH_PEM:
1503 case IDC_EXPORT_OPENSSH_NEW:
1504 case IDC_EXPORT_SSHCOM:
1505 topic = WINHELP_CTX_puttygen_conversions; break;
1508 launch_help(hwnd, topic);
1515 state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1524 void cleanup_exit(int code)
1530 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
1536 InitCommonControls();
1541 * See if we can find our Help file.
1545 split_into_argv(cmdline, &argc, &argv, NULL);
1548 if (!strcmp(argv[0], "-pgpfp")) {
1553 * Assume the first argument to be a private key file, and
1554 * attempt to load it.
1556 cmdline_keyfile = argv[0];
1561 ret = DialogBox(hinst, MAKEINTRESOURCE(201), NULL, MainDlgProc) != IDOK;
1564 return ret; /* just in case optimiser complains */