2 * PuTTY key generation front end.
11 #define PUTTY_DO_GLOBALS
17 #define WM_DONEKEY (WM_XUSER + 1)
19 #define DEFAULT_KEYSIZE 1024
21 /* ----------------------------------------------------------------------
22 * Progress report code. This is really horrible :-)
24 #define PROGRESSRANGE 65535
30 unsigned startpoint, total;
31 unsigned param, current, n; /* if exponential */
32 unsigned mult; /* if linear */
34 unsigned total, divisor, range;
38 static void progress_update(void *param, int action, int phase, int iprogress)
40 struct progress *p = (struct progress *) param;
41 unsigned progress = iprogress;
44 if (action < PROGFN_READY && p->nphases < phase)
47 case PROGFN_INITIALISE:
50 case PROGFN_LIN_PHASE:
51 p->phases[phase-1].exponential = 0;
52 p->phases[phase-1].mult = p->phases[phase].total / progress;
54 case PROGFN_EXP_PHASE:
55 p->phases[phase-1].exponential = 1;
56 p->phases[phase-1].param = 0x10000 + progress;
57 p->phases[phase-1].current = p->phases[phase-1].total;
58 p->phases[phase-1].n = 0;
60 case PROGFN_PHASE_EXTENT:
61 p->phases[phase-1].total = progress;
67 for (i = 0; i < p->nphases; i++) {
68 p->phases[i].startpoint = total;
69 total += p->phases[i].total;
72 p->divisor = ((p->total + PROGRESSRANGE - 1) / PROGRESSRANGE);
73 p->range = p->total / p->divisor;
74 SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, p->range));
78 if (p->phases[phase-1].exponential) {
79 while (p->phases[phase-1].n < progress) {
80 p->phases[phase-1].n++;
81 p->phases[phase-1].current *= p->phases[phase-1].param;
82 p->phases[phase-1].current /= 0x10000;
84 position = (p->phases[phase-1].startpoint +
85 p->phases[phase-1].total - p->phases[phase-1].current);
87 position = (p->phases[phase-1].startpoint +
88 progress * p->phases[phase-1].mult);
90 SendMessage(p->progbar, PBM_SETPOS, position / p->divisor, 0);
97 #define PASSPHRASE_MAXLEN 512
99 struct PassphraseProcStruct {
105 * Dialog-box function for the passphrase box.
107 static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
108 WPARAM wParam, LPARAM lParam)
110 static char *passphrase = NULL;
111 struct PassphraseProcStruct *p;
115 SetForegroundWindow(hwnd);
116 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
117 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
122 { /* centre the window */
126 hw = GetDesktopWindow();
127 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
129 (rs.right + rs.left + rd.left - rd.right) / 2,
130 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
131 rd.right - rd.left, rd.bottom - rd.top, TRUE);
134 p = (struct PassphraseProcStruct *) lParam;
135 passphrase = p->passphrase;
137 SetDlgItemText(hwnd, 101, p->comment);
139 SetDlgItemText(hwnd, 102, passphrase);
142 switch (LOWORD(wParam)) {
152 case 102: /* edit box */
153 if ((HIWORD(wParam) == EN_CHANGE) && passphrase) {
154 GetDlgItemText(hwnd, 102, passphrase,
155 PASSPHRASE_MAXLEN - 1);
156 passphrase[PASSPHRASE_MAXLEN - 1] = '\0';
169 * Prompt for a key file. Assumes the filename buffer is of size
172 static int prompt_keyfile(HWND hwnd, char *dlgtitle,
173 char *filename, int save)
176 memset(&of, 0, sizeof(of));
177 #ifdef OPENFILENAME_SIZE_VERSION_400
178 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
180 of.lStructSize = sizeof(of);
183 of.lpstrFilter = "All Files\0*\0\0\0";
184 of.lpstrCustomFilter = NULL;
186 of.lpstrFile = filename;
188 of.nMaxFile = FILENAME_MAX;
189 of.lpstrFileTitle = NULL;
190 of.lpstrInitialDir = NULL;
191 of.lpstrTitle = dlgtitle;
194 return GetSaveFileName(&of);
196 return GetOpenFileName(&of);
200 * This function is needed to link with the DES code. We need not
201 * have it do anything at all.
203 void logevent(char *msg)
208 * Dialog-box function for the Licence box.
210 static int CALLBACK LicenceProc(HWND hwnd, UINT msg,
211 WPARAM wParam, LPARAM lParam)
218 { /* centre the window */
222 hw = GetDesktopWindow();
223 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
225 (rs.right + rs.left + rd.left - rd.right) / 2,
226 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
227 rd.right - rd.left, rd.bottom - rd.top, TRUE);
232 switch (LOWORD(wParam)) {
246 * Dialog-box function for the About box.
248 static int CALLBACK AboutProc(HWND hwnd, UINT msg,
249 WPARAM wParam, LPARAM lParam)
256 { /* centre the window */
260 hw = GetDesktopWindow();
261 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
263 (rs.right + rs.left + rd.left - rd.right) / 2,
264 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
265 rd.right - rd.left, rd.bottom - rd.top, TRUE);
268 SetDlgItemText(hwnd, 100, ver);
271 switch (LOWORD(wParam)) {
276 EnableWindow(hwnd, 0);
277 DialogBox(hinst, MAKEINTRESOURCE(214), NULL, LicenceProc);
278 EnableWindow(hwnd, 1);
279 SetActiveWindow(hwnd);
291 * Thread to generate a key.
293 struct rsa_key_thread_params {
294 HWND progressbar; /* notify this with progress */
295 HWND dialog; /* notify this on completion */
296 int keysize; /* bits in key */
299 struct dss_key *dsskey;
301 static DWORD WINAPI generate_rsa_key_thread(void *param)
303 struct rsa_key_thread_params *params =
304 (struct rsa_key_thread_params *) param;
305 struct progress prog;
306 prog.progbar = params->progressbar;
308 progress_update(&prog, PROGFN_INITIALISE, 0, 0);
311 dsa_generate(params->dsskey, params->keysize, progress_update, &prog);
313 rsa_generate(params->key, params->keysize, progress_update, &prog);
315 PostMessage(params->dialog, WM_DONEKEY, 0, 0);
321 struct MainDlgState {
322 int collecting_entropy;
323 int generation_thread_exists;
325 int entropy_got, entropy_required, entropy_size;
328 char **commentptr; /* points to key.comment or ssh2key.comment */
329 struct ssh2_userkey ssh2key;
332 struct dss_key dsskey;
335 static void hidemany(HWND hwnd, const int *ids, int hideit)
338 ShowWindow(GetDlgItem(hwnd, *ids++), (hideit ? SW_HIDE : SW_SHOW));
342 static void setupbigedit1(HWND hwnd, int id, int idstatic, struct RSAKey *key)
347 dec1 = bignum_decimal(key->exponent);
348 dec2 = bignum_decimal(key->modulus);
349 buffer = smalloc(strlen(dec1) + strlen(dec2) +
350 strlen(key->comment) + 30);
351 sprintf(buffer, "%d %s %s %s",
352 bignum_bitcount(key->modulus), dec1, dec2, key->comment);
353 SetDlgItemText(hwnd, id, buffer);
354 SetDlgItemText(hwnd, idstatic,
355 "&Public key for pasting into authorized_keys file:");
361 static void setupbigedit2(HWND hwnd, int id, int idstatic,
362 struct ssh2_userkey *key)
364 unsigned char *pub_blob;
369 pub_blob = key->alg->public_blob(key->data, &pub_len);
370 buffer = smalloc(strlen(key->alg->name) + 4 * ((pub_len + 2) / 3) +
371 strlen(key->comment) + 3);
372 strcpy(buffer, key->alg->name);
373 p = buffer + strlen(buffer);
376 while (i < pub_len) {
377 int n = (pub_len - i < 3 ? pub_len - i : 3);
378 base64_encode_atom(pub_blob + i, n, p);
383 strcpy(p, key->comment);
384 SetDlgItemText(hwnd, id, buffer);
385 SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
386 "OpenSSH authorized_keys2 file:");
391 static int save_ssh1_pubkey(char *filename, struct RSAKey *key)
396 dec1 = bignum_decimal(key->exponent);
397 dec2 = bignum_decimal(key->modulus);
398 fp = fopen(filename, "wb");
401 fprintf(fp, "%d %s %s %s\n",
402 bignum_bitcount(key->modulus), dec1, dec2, key->comment);
410 * Warn about the obsolescent key file format.
412 void old_keyfile_warning(void)
414 static const char mbtitle[] = "PuTTY Key File Warning";
415 static const char message[] =
416 "You are loading an SSH 2 private key which has an\n"
417 "old version of the file format. This means your key\n"
418 "file is not fully tamperproof. Future versions of\n"
419 "PuTTY may stop supporting this private key format,\n"
420 "so we recommend you convert your key to the new\n"
423 "Once the key is loaded into PuTTYgen, you can perform\n"
424 "this conversion simply by saving it again.";
426 MessageBox(NULL, message, mbtitle, MB_OK);
429 static int save_ssh2_pubkey(char *filename, struct ssh2_userkey *key)
431 unsigned char *pub_blob;
437 pub_blob = key->alg->public_blob(key->data, &pub_len);
439 fp = fopen(filename, "wb");
443 fprintf(fp, "---- BEGIN SSH2 PUBLIC KEY ----\n");
445 fprintf(fp, "Comment: \"");
446 for (p = key->comment; *p; p++) {
447 if (*p == '\\' || *p == '\"')
455 while (i < pub_len) {
457 int n = (pub_len - i < 3 ? pub_len - i : 3);
458 base64_encode_atom(pub_blob + i, n, buf);
462 if (++column >= 16) {
470 fprintf(fp, "---- END SSH2 PUBLIC KEY ----\n");
477 * Dialog-box function for the main PuTTYgen dialog box.
479 static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
480 WPARAM wParam, LPARAM lParam)
483 controlidstart = 100,
489 IDC_PKSTATIC, IDC_KEYDISPLAY,
490 IDC_FPSTATIC, IDC_FINGERPRINT,
491 IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
492 IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
493 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT,
495 IDC_GENSTATIC, IDC_GENERATE,
496 IDC_LOADSTATIC, IDC_LOAD,
497 IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
499 IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
500 IDC_BITSSTATIC, IDC_BITS,
503 static const int nokey_ids[] = { IDC_NOKEY, 0 };
504 static const int generating_ids[] =
505 { IDC_GENERATING, IDC_PROGRESS, 0 };
506 static const int gotkey_ids[] = {
507 IDC_PKSTATIC, IDC_KEYDISPLAY,
508 IDC_FPSTATIC, IDC_FINGERPRINT,
509 IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
510 IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
511 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 0
513 static const char generating_msg[] =
514 "Please wait while a key is generated...";
515 static const char entropy_msg[] =
516 "Please generate some randomness by moving the mouse over the blank area.";
517 struct MainDlgState *state;
524 { /* centre the window */
528 hw = GetDesktopWindow();
529 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
531 (rs.right + rs.left + rd.left - rd.right) / 2,
532 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
533 rd.right - rd.left, rd.bottom - rd.top, TRUE);
536 state = smalloc(sizeof(*state));
537 state->generation_thread_exists = FALSE;
538 state->collecting_entropy = FALSE;
539 state->entropy = NULL;
540 state->key_exists = FALSE;
541 SetWindowLong(hwnd, GWL_USERDATA, (LONG) state);
543 struct ctlpos cp, cp2;
545 /* Accelerators used: acglops1rbd */
547 ctlposinit(&cp, hwnd, 4, 4, 4);
548 bartitle(&cp, "Public and private key generation for PuTTY",
550 beginbox(&cp, "Key", IDC_BOX_KEY);
552 statictext(&cp2, "No key.", 1, IDC_NOKEY);
554 statictext(&cp2, "", 1, IDC_GENERATING);
555 progressbar(&cp2, IDC_PROGRESS);
557 "&Public key for pasting into authorized_keys file:",
558 IDC_PKSTATIC, IDC_KEYDISPLAY, 5);
559 SendDlgItemMessage(hwnd, IDC_KEYDISPLAY, EM_SETREADONLY, 1, 0);
560 staticedit(&cp, "Key fingerprint:", IDC_FPSTATIC,
561 IDC_FINGERPRINT, 75);
562 SendDlgItemMessage(hwnd, IDC_FINGERPRINT, EM_SETREADONLY, 1,
564 staticedit(&cp, "Key &comment:", IDC_COMMENTSTATIC,
565 IDC_COMMENTEDIT, 75);
566 staticpassedit(&cp, "Key p&assphrase:", IDC_PASSPHRASE1STATIC,
567 IDC_PASSPHRASE1EDIT, 75);
568 staticpassedit(&cp, "C&onfirm passphrase:",
569 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 75);
571 beginbox(&cp, "Actions", IDC_BOX_ACTIONS);
572 staticbtn(&cp, "Generate a public/private key pair",
573 IDC_GENSTATIC, "&Generate", IDC_GENERATE);
574 staticbtn(&cp, "Load an existing private key file",
575 IDC_LOADSTATIC, "&Load", IDC_LOAD);
576 static2btn(&cp, "Save the generated key", IDC_SAVESTATIC,
577 "Save p&ublic key", IDC_SAVEPUB,
578 "&Save private key", IDC_SAVE);
580 beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
581 radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 3,
582 "SSH&1 (RSA)", IDC_KEYSSH1,
583 "SSH2 &RSA", IDC_KEYSSH2RSA,
584 "SSH2 &DSA", IDC_KEYSSH2DSA, NULL);
585 staticedit(&cp, "Number of &bits in a generated key:",
586 IDC_BITSSTATIC, IDC_BITS, 20);
589 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA, IDC_KEYSSH1);
590 SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE);
593 * Initially, hide the progress bar and the key display,
594 * and show the no-key display. Also disable the Save
595 * buttons, because with no key we obviously can't save
598 hidemany(hwnd, nokey_ids, FALSE);
599 hidemany(hwnd, generating_ids, TRUE);
600 hidemany(hwnd, gotkey_ids, TRUE);
601 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
602 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
606 state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
607 if (state->collecting_entropy &&
608 state->entropy && state->entropy_got < state->entropy_required) {
609 state->entropy[state->entropy_got++] = lParam;
610 state->entropy[state->entropy_got++] = GetMessageTime();
611 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS,
612 state->entropy_got, 0);
613 if (state->entropy_got >= state->entropy_required) {
614 struct rsa_key_thread_params *params;
618 * Seed the entropy pool
620 random_add_heavynoise(state->entropy, state->entropy_size);
621 memset(state->entropy, 0, state->entropy_size);
622 sfree(state->entropy);
623 state->collecting_entropy = FALSE;
625 SetDlgItemText(hwnd, IDC_GENERATING, generating_msg);
626 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
627 MAKELPARAM(0, PROGRESSRANGE));
628 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
630 params = smalloc(sizeof(*params));
631 params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
632 params->dialog = hwnd;
633 params->keysize = state->keysize;
634 params->is_dsa = state->is_dsa;
635 params->key = &state->key;
636 params->dsskey = &state->dsskey;
638 if (!CreateThread(NULL, 0, generate_rsa_key_thread,
639 params, 0, &threadid)) {
640 MessageBox(hwnd, "Out of thread resources",
641 "Key generation error",
642 MB_OK | MB_ICONERROR);
645 state->generation_thread_exists = TRUE;
651 switch (LOWORD(wParam)) {
652 case IDC_COMMENTEDIT:
653 if (HIWORD(wParam) == EN_CHANGE) {
654 state = (struct MainDlgState *)
655 GetWindowLong(hwnd, GWL_USERDATA);
656 if (state->key_exists) {
657 HWND editctl = GetDlgItem(hwnd, IDC_COMMENTEDIT);
658 int len = GetWindowTextLength(editctl);
659 if (*state->commentptr)
660 sfree(*state->commentptr);
661 *state->commentptr = smalloc(len + 1);
662 GetWindowText(editctl, *state->commentptr, len + 1);
664 setupbigedit2(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
667 setupbigedit1(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
674 EnableWindow(hwnd, 0);
675 DialogBox(hinst, MAKEINTRESOURCE(213), NULL, AboutProc);
676 EnableWindow(hwnd, 1);
677 SetActiveWindow(hwnd);
681 (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
682 if (!state->generation_thread_exists) {
684 state->keysize = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE);
686 state->keysize = DEFAULT_KEYSIZE;
687 /* If we ever introduce a new key type, check it here! */
688 state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
689 state->is_dsa = IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA);
690 if (state->keysize < 256) {
691 int ret = MessageBox(hwnd,
692 "PuTTYgen will not generate a key"
693 " smaller than 256 bits.\n"
694 "Key length reset to 256. Continue?",
696 MB_ICONWARNING | MB_OKCANCEL);
699 state->keysize = 256;
700 SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
702 hidemany(hwnd, nokey_ids, TRUE);
703 hidemany(hwnd, generating_ids, FALSE);
704 hidemany(hwnd, gotkey_ids, TRUE);
705 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0);
706 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0);
707 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
708 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
709 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0);
710 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
711 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0);
712 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
713 state->key_exists = FALSE;
714 SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
715 state->collecting_entropy = TRUE;
718 * My brief statistical tests on mouse movements
719 * suggest that there are about 2.5 bits of
720 * randomness in the x position, 2.5 in the y
721 * position, and 1.7 in the message time, making
722 * 5.7 bits of unpredictability per mouse movement.
723 * However, other people have told me it's far less
724 * than that, so I'm going to be stupidly cautious
725 * and knock that down to a nice round 2. With this
726 * method, we require two words per mouse movement,
727 * so with 2 bits per mouse movement we expect 2
728 * bits every 2 words.
730 state->entropy_required = (state->keysize / 2) * 2;
731 state->entropy_got = 0;
732 state->entropy_size = (state->entropy_required *
733 sizeof(*state->entropy));
734 state->entropy = smalloc(state->entropy_size);
736 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
737 MAKELPARAM(0, state->entropy_required));
738 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
743 (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
744 if (state->key_exists) {
745 char filename[FILENAME_MAX];
746 char passphrase[PASSPHRASE_MAXLEN];
747 char passphrase2[PASSPHRASE_MAXLEN];
748 GetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
749 passphrase, sizeof(passphrase));
750 GetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
751 passphrase2, sizeof(passphrase2));
752 if (strcmp(passphrase, passphrase2)) {
754 "The two passphrases given do not match.",
755 "PuTTYgen Error", MB_OK | MB_ICONERROR);
760 ret = MessageBox(hwnd,
761 "Are you sure you want to save this key\n"
762 "without a passphrase to protect it?",
764 MB_YESNO | MB_ICONWARNING);
768 if (prompt_keyfile(hwnd, "Save private key as:",
771 FILE *fp = fopen(filename, "r");
773 char buffer[FILENAME_MAX + 80];
775 sprintf(buffer, "Overwrite existing file\n%.*s?",
776 FILENAME_MAX, filename);
777 ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
778 MB_YESNO | MB_ICONWARNING);
783 ret = ssh2_save_userkey(filename, &state->ssh2key,
784 *passphrase ? passphrase :
787 ret = saversakey(filename, &state->key,
788 *passphrase ? passphrase : NULL);
791 MessageBox(hwnd, "Unable to save key file",
792 "PuTTYgen Error", MB_OK | MB_ICONERROR);
799 (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
800 if (state->key_exists) {
801 char filename[FILENAME_MAX];
802 if (prompt_keyfile(hwnd, "Save public key as:",
805 FILE *fp = fopen(filename, "r");
807 char buffer[FILENAME_MAX + 80];
809 sprintf(buffer, "Overwrite existing file\n%.*s?",
810 FILENAME_MAX, filename);
811 ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
812 MB_YESNO | MB_ICONWARNING);
817 ret = save_ssh2_pubkey(filename, &state->ssh2key);
819 ret = save_ssh1_pubkey(filename, &state->key);
822 MessageBox(hwnd, "Unable to save key file",
823 "PuTTYgen Error", MB_OK | MB_ICONERROR);
830 (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
831 if (!state->generation_thread_exists) {
832 char filename[FILENAME_MAX];
833 if (prompt_keyfile(hwnd, "Load private key:", filename, 0)) {
834 char passphrase[PASSPHRASE_MAXLEN];
839 struct PassphraseProcStruct pps;
840 struct RSAKey newkey1;
841 struct ssh2_userkey *newkey2 = NULL;
843 ver = keyfile_version(filename);
845 MessageBox(NULL, "Couldn't load private key.",
846 "PuTTYgen Error", MB_OK | MB_ICONERROR);
852 needs_pass = rsakey_encrypted(filename, &comment);
855 ssh2_userkey_encrypted(filename, &comment);
856 pps.passphrase = passphrase;
857 pps.comment = comment;
861 dlgret = DialogBoxParam(hinst,
862 MAKEINTRESOURCE(210),
863 NULL, PassphraseProc,
873 loadrsakey(filename, &newkey1, passphrase);
876 ssh2_load_userkey(filename, passphrase);
877 if (newkey2 == SSH2_WRONG_PASSPHRASE)
888 MessageBox(NULL, "Couldn't load private key.",
889 "PuTTYgen Error", MB_OK | MB_ICONERROR);
890 } else if (ret == 1) {
891 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
892 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
893 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
894 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
895 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
896 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
897 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
898 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
900 * Now update the key controls with all the
904 SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
906 SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
913 state->commentptr = &state->key.comment;
914 state->key = newkey1;
917 * Set the key fingerprint.
919 savecomment = state->key.comment;
920 state->key.comment = NULL;
921 rsa_fingerprint(buf, sizeof(buf),
923 state->key.comment = savecomment;
925 SetDlgItemText(hwnd, IDC_FINGERPRINT, buf);
927 * Construct a decimal representation
928 * of the key, for pasting into
929 * .ssh/authorized_keys on a Unix box.
931 setupbigedit1(hwnd, IDC_KEYDISPLAY,
932 IDC_PKSTATIC, &state->key);
939 &state->ssh2key.comment;
940 state->ssh2key = *newkey2; /* structure copy */
943 savecomment = state->ssh2key.comment;
944 state->ssh2key.comment = NULL;
947 fingerprint(state->ssh2key.data);
948 state->ssh2key.comment = savecomment;
950 SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
953 setupbigedit2(hwnd, IDC_KEYDISPLAY,
954 IDC_PKSTATIC, &state->ssh2key);
956 SetDlgItemText(hwnd, IDC_COMMENTEDIT,
960 * Finally, hide the progress bar and show
963 hidemany(hwnd, nokey_ids, TRUE);
964 hidemany(hwnd, generating_ids, TRUE);
965 hidemany(hwnd, gotkey_ids, FALSE);
966 state->key_exists = TRUE;
974 state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
975 state->generation_thread_exists = FALSE;
976 state->key_exists = TRUE;
977 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
978 MAKELPARAM(0, PROGRESSRANGE));
979 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0);
980 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
981 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
982 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
983 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
984 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
985 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
986 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
987 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
990 state->ssh2key.data = &state->dsskey;
991 state->ssh2key.alg = &ssh_dss;
993 state->ssh2key.data = &state->key;
994 state->ssh2key.alg = &ssh_rsa;
996 state->commentptr = &state->ssh2key.comment;
998 state->commentptr = &state->key.comment;
1001 * Invent a comment for the key. We'll do this by including
1002 * the date in it. This will be so horrifyingly ugly that
1003 * the user will immediately want to change it, which is
1006 *state->commentptr = smalloc(30);
1013 strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", tm);
1015 strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", tm);
1019 * Now update the key controls with all the key data.
1024 * Blank passphrase, initially. This isn't dangerous,
1025 * because we will warn (Are You Sure?) before allowing
1026 * the user to save an unprotected private key.
1028 SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, "");
1029 SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, "");
1033 SetDlgItemText(hwnd, IDC_COMMENTEDIT, *state->commentptr);
1035 * Set the key fingerprint.
1037 savecomment = *state->commentptr;
1038 *state->commentptr = NULL;
1041 fp = state->ssh2key.alg->fingerprint(state->ssh2key.data);
1042 SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
1046 rsa_fingerprint(buf, sizeof(buf), &state->key);
1047 SetDlgItemText(hwnd, IDC_FINGERPRINT, buf);
1049 *state->commentptr = savecomment;
1051 * Construct a decimal representation of the key, for
1052 * pasting into .ssh/authorized_keys or
1053 * .ssh/authorized_keys2 on a Unix box.
1056 setupbigedit2(hwnd, IDC_KEYDISPLAY,
1057 IDC_PKSTATIC, &state->ssh2key);
1059 setupbigedit1(hwnd, IDC_KEYDISPLAY,
1060 IDC_PKSTATIC, &state->key);
1064 * Finally, hide the progress bar and show the key data.
1066 hidemany(hwnd, nokey_ids, TRUE);
1067 hidemany(hwnd, generating_ids, TRUE);
1068 hidemany(hwnd, gotkey_ids, FALSE);
1071 state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
1079 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
1081 InitCommonControls();
1084 return DialogBox(hinst, MAKEINTRESOURCE(201), NULL,
1085 MainDlgProc) != IDOK;