Failure to initialise a local variable was leading to free(garbage)
[u/mdw/putty] / puttygen.c
1 /*
2 * PuTTY key generation front end.
3 */
4
5 #include <windows.h>
6 #include <commctrl.h>
7 #include <time.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #define PUTTY_DO_GLOBALS
12
13 #include "putty.h"
14 #include "ssh.h"
15 #include "winstuff.h"
16
17 #define WM_DONEKEY (WM_XUSER + 1)
18
19 #define DEFAULT_KEYSIZE 1024
20
21 static int requested_help;
22
23 /* ----------------------------------------------------------------------
24 * Progress report code. This is really horrible :-)
25 */
26 #define PROGRESSRANGE 65535
27 #define MAXPHASE 5
28 struct progress {
29 int nphases;
30 struct {
31 int exponential;
32 unsigned startpoint, total;
33 unsigned param, current, n; /* if exponential */
34 unsigned mult; /* if linear */
35 } phases[MAXPHASE];
36 unsigned total, divisor, range;
37 HWND progbar;
38 };
39
40 static void progress_update(void *param, int action, int phase, int iprogress)
41 {
42 struct progress *p = (struct progress *) param;
43 unsigned progress = iprogress;
44 int position;
45
46 if (action < PROGFN_READY && p->nphases < phase)
47 p->nphases = phase;
48 switch (action) {
49 case PROGFN_INITIALISE:
50 p->nphases = 0;
51 break;
52 case PROGFN_LIN_PHASE:
53 p->phases[phase-1].exponential = 0;
54 p->phases[phase-1].mult = p->phases[phase].total / progress;
55 break;
56 case PROGFN_EXP_PHASE:
57 p->phases[phase-1].exponential = 1;
58 p->phases[phase-1].param = 0x10000 + progress;
59 p->phases[phase-1].current = p->phases[phase-1].total;
60 p->phases[phase-1].n = 0;
61 break;
62 case PROGFN_PHASE_EXTENT:
63 p->phases[phase-1].total = progress;
64 break;
65 case PROGFN_READY:
66 {
67 unsigned total = 0;
68 int i;
69 for (i = 0; i < p->nphases; i++) {
70 p->phases[i].startpoint = total;
71 total += p->phases[i].total;
72 }
73 p->total = total;
74 p->divisor = ((p->total + PROGRESSRANGE - 1) / PROGRESSRANGE);
75 p->range = p->total / p->divisor;
76 SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, p->range));
77 }
78 break;
79 case PROGFN_PROGRESS:
80 if (p->phases[phase-1].exponential) {
81 while (p->phases[phase-1].n < progress) {
82 p->phases[phase-1].n++;
83 p->phases[phase-1].current *= p->phases[phase-1].param;
84 p->phases[phase-1].current /= 0x10000;
85 }
86 position = (p->phases[phase-1].startpoint +
87 p->phases[phase-1].total - p->phases[phase-1].current);
88 } else {
89 position = (p->phases[phase-1].startpoint +
90 progress * p->phases[phase-1].mult);
91 }
92 SendMessage(p->progbar, PBM_SETPOS, position / p->divisor, 0);
93 break;
94 }
95 }
96
97 extern char ver[];
98
99 #define PASSPHRASE_MAXLEN 512
100
101 struct PassphraseProcStruct {
102 char *passphrase;
103 char *comment;
104 };
105
106 /*
107 * Dialog-box function for the passphrase box.
108 */
109 static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
110 WPARAM wParam, LPARAM lParam)
111 {
112 static char *passphrase = NULL;
113 struct PassphraseProcStruct *p;
114
115 switch (msg) {
116 case WM_INITDIALOG:
117 SetForegroundWindow(hwnd);
118 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
119 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
120
121 /*
122 * Centre the window.
123 */
124 { /* centre the window */
125 RECT rs, rd;
126 HWND hw;
127
128 hw = GetDesktopWindow();
129 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
130 MoveWindow(hwnd,
131 (rs.right + rs.left + rd.left - rd.right) / 2,
132 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
133 rd.right - rd.left, rd.bottom - rd.top, TRUE);
134 }
135
136 p = (struct PassphraseProcStruct *) lParam;
137 passphrase = p->passphrase;
138 if (p->comment)
139 SetDlgItemText(hwnd, 101, p->comment);
140 *passphrase = 0;
141 SetDlgItemText(hwnd, 102, passphrase);
142 return 0;
143 case WM_COMMAND:
144 switch (LOWORD(wParam)) {
145 case IDOK:
146 if (*passphrase)
147 EndDialog(hwnd, 1);
148 else
149 MessageBeep(0);
150 return 0;
151 case IDCANCEL:
152 EndDialog(hwnd, 0);
153 return 0;
154 case 102: /* edit box */
155 if ((HIWORD(wParam) == EN_CHANGE) && passphrase) {
156 GetDlgItemText(hwnd, 102, passphrase,
157 PASSPHRASE_MAXLEN - 1);
158 passphrase[PASSPHRASE_MAXLEN - 1] = '\0';
159 }
160 return 0;
161 }
162 return 0;
163 case WM_CLOSE:
164 EndDialog(hwnd, 0);
165 return 0;
166 }
167 return 0;
168 }
169
170 /*
171 * Prompt for a key file. Assumes the filename buffer is of size
172 * FILENAME_MAX.
173 */
174 static int prompt_keyfile(HWND hwnd, char *dlgtitle,
175 char *filename, int save)
176 {
177 OPENFILENAME of;
178 memset(&of, 0, sizeof(of));
179 #ifdef OPENFILENAME_SIZE_VERSION_400
180 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
181 #else
182 of.lStructSize = sizeof(of);
183 #endif
184 of.hwndOwner = hwnd;
185 of.lpstrFilter = "All Files\0*\0\0\0";
186 of.lpstrCustomFilter = NULL;
187 of.nFilterIndex = 1;
188 of.lpstrFile = filename;
189 *filename = '\0';
190 of.nMaxFile = FILENAME_MAX;
191 of.lpstrFileTitle = NULL;
192 of.lpstrInitialDir = NULL;
193 of.lpstrTitle = dlgtitle;
194 of.Flags = 0;
195 if (save)
196 return GetSaveFileName(&of);
197 else
198 return GetOpenFileName(&of);
199 }
200
201 /*
202 * This function is needed to link with the DES code. We need not
203 * have it do anything at all.
204 */
205 void logevent(char *msg)
206 {
207 }
208
209 /*
210 * Dialog-box function for the Licence box.
211 */
212 static int CALLBACK LicenceProc(HWND hwnd, UINT msg,
213 WPARAM wParam, LPARAM lParam)
214 {
215 switch (msg) {
216 case WM_INITDIALOG:
217 /*
218 * Centre the window.
219 */
220 { /* centre the window */
221 RECT rs, rd;
222 HWND hw;
223
224 hw = GetDesktopWindow();
225 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
226 MoveWindow(hwnd,
227 (rs.right + rs.left + rd.left - rd.right) / 2,
228 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
229 rd.right - rd.left, rd.bottom - rd.top, TRUE);
230 }
231
232 return 1;
233 case WM_COMMAND:
234 switch (LOWORD(wParam)) {
235 case IDOK:
236 EndDialog(hwnd, 1);
237 return 0;
238 }
239 return 0;
240 case WM_CLOSE:
241 EndDialog(hwnd, 1);
242 return 0;
243 }
244 return 0;
245 }
246
247 /*
248 * Dialog-box function for the About box.
249 */
250 static int CALLBACK AboutProc(HWND hwnd, UINT msg,
251 WPARAM wParam, LPARAM lParam)
252 {
253 switch (msg) {
254 case WM_INITDIALOG:
255 /*
256 * Centre the window.
257 */
258 { /* centre the window */
259 RECT rs, rd;
260 HWND hw;
261
262 hw = GetDesktopWindow();
263 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
264 MoveWindow(hwnd,
265 (rs.right + rs.left + rd.left - rd.right) / 2,
266 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
267 rd.right - rd.left, rd.bottom - rd.top, TRUE);
268 }
269
270 SetDlgItemText(hwnd, 100, ver);
271 return 1;
272 case WM_COMMAND:
273 switch (LOWORD(wParam)) {
274 case IDOK:
275 EndDialog(hwnd, 1);
276 return 0;
277 case 101:
278 EnableWindow(hwnd, 0);
279 DialogBox(hinst, MAKEINTRESOURCE(214), NULL, LicenceProc);
280 EnableWindow(hwnd, 1);
281 SetActiveWindow(hwnd);
282 return 0;
283 }
284 return 0;
285 case WM_CLOSE:
286 EndDialog(hwnd, 1);
287 return 0;
288 }
289 return 0;
290 }
291
292 /*
293 * Thread to generate a key.
294 */
295 struct rsa_key_thread_params {
296 HWND progressbar; /* notify this with progress */
297 HWND dialog; /* notify this on completion */
298 int keysize; /* bits in key */
299 int is_dsa;
300 struct RSAKey *key;
301 struct dss_key *dsskey;
302 };
303 static DWORD WINAPI generate_rsa_key_thread(void *param)
304 {
305 struct rsa_key_thread_params *params =
306 (struct rsa_key_thread_params *) param;
307 struct progress prog;
308 prog.progbar = params->progressbar;
309
310 progress_update(&prog, PROGFN_INITIALISE, 0, 0);
311
312 if (params->is_dsa)
313 dsa_generate(params->dsskey, params->keysize, progress_update, &prog);
314 else
315 rsa_generate(params->key, params->keysize, progress_update, &prog);
316
317 PostMessage(params->dialog, WM_DONEKEY, 0, 0);
318
319 sfree(params);
320 return 0;
321 }
322
323 struct MainDlgState {
324 int collecting_entropy;
325 int generation_thread_exists;
326 int key_exists;
327 int entropy_got, entropy_required, entropy_size;
328 int keysize;
329 int ssh2, is_dsa;
330 char **commentptr; /* points to key.comment or ssh2key.comment */
331 struct ssh2_userkey ssh2key;
332 unsigned *entropy;
333 struct RSAKey key;
334 struct dss_key dsskey;
335 HMENU filemenu, keymenu, cvtmenu;
336 };
337
338 static void hidemany(HWND hwnd, const int *ids, int hideit)
339 {
340 while (*ids) {
341 ShowWindow(GetDlgItem(hwnd, *ids++), (hideit ? SW_HIDE : SW_SHOW));
342 }
343 }
344
345 static void setupbigedit1(HWND hwnd, int id, int idstatic, struct RSAKey *key)
346 {
347 char *buffer;
348 char *dec1, *dec2;
349
350 dec1 = bignum_decimal(key->exponent);
351 dec2 = bignum_decimal(key->modulus);
352 buffer = smalloc(strlen(dec1) + strlen(dec2) +
353 strlen(key->comment) + 30);
354 sprintf(buffer, "%d %s %s %s",
355 bignum_bitcount(key->modulus), dec1, dec2, key->comment);
356 SetDlgItemText(hwnd, id, buffer);
357 SetDlgItemText(hwnd, idstatic,
358 "&Public key for pasting into authorized_keys file:");
359 sfree(dec1);
360 sfree(dec2);
361 sfree(buffer);
362 }
363
364 static void setupbigedit2(HWND hwnd, int id, int idstatic,
365 struct ssh2_userkey *key)
366 {
367 unsigned char *pub_blob;
368 char *buffer, *p;
369 int pub_len;
370 int i;
371
372 pub_blob = key->alg->public_blob(key->data, &pub_len);
373 buffer = smalloc(strlen(key->alg->name) + 4 * ((pub_len + 2) / 3) +
374 strlen(key->comment) + 3);
375 strcpy(buffer, key->alg->name);
376 p = buffer + strlen(buffer);
377 *p++ = ' ';
378 i = 0;
379 while (i < pub_len) {
380 int n = (pub_len - i < 3 ? pub_len - i : 3);
381 base64_encode_atom(pub_blob + i, n, p);
382 i += n;
383 p += 4;
384 }
385 *p++ = ' ';
386 strcpy(p, key->comment);
387 SetDlgItemText(hwnd, id, buffer);
388 SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
389 "OpenSSH authorized_keys2 file:");
390 sfree(pub_blob);
391 sfree(buffer);
392 }
393
394 static int save_ssh1_pubkey(char *filename, struct RSAKey *key)
395 {
396 char *dec1, *dec2;
397 FILE *fp;
398
399 dec1 = bignum_decimal(key->exponent);
400 dec2 = bignum_decimal(key->modulus);
401 fp = fopen(filename, "wb");
402 if (!fp)
403 return 0;
404 fprintf(fp, "%d %s %s %s\n",
405 bignum_bitcount(key->modulus), dec1, dec2, key->comment);
406 fclose(fp);
407 sfree(dec1);
408 sfree(dec2);
409 return 1;
410 }
411
412 /*
413 * Warn about the obsolescent key file format.
414 */
415 void old_keyfile_warning(void)
416 {
417 static const char mbtitle[] = "PuTTY Key File Warning";
418 static const char message[] =
419 "You are loading an SSH 2 private key which has an\n"
420 "old version of the file format. This means your key\n"
421 "file is not fully tamperproof. Future versions of\n"
422 "PuTTY may stop supporting this private key format,\n"
423 "so we recommend you convert your key to the new\n"
424 "format.\n"
425 "\n"
426 "Once the key is loaded into PuTTYgen, you can perform\n"
427 "this conversion simply by saving it again.";
428
429 MessageBox(NULL, message, mbtitle, MB_OK);
430 }
431
432 static int save_ssh2_pubkey(char *filename, struct ssh2_userkey *key)
433 {
434 unsigned char *pub_blob;
435 char *p;
436 int pub_len;
437 int i, column;
438 FILE *fp;
439
440 pub_blob = key->alg->public_blob(key->data, &pub_len);
441
442 fp = fopen(filename, "wb");
443 if (!fp)
444 return 0;
445
446 fprintf(fp, "---- BEGIN SSH2 PUBLIC KEY ----\n");
447
448 fprintf(fp, "Comment: \"");
449 for (p = key->comment; *p; p++) {
450 if (*p == '\\' || *p == '\"')
451 fputc('\\', fp);
452 fputc(*p, fp);
453 }
454 fprintf(fp, "\"\n");
455
456 i = 0;
457 column = 0;
458 while (i < pub_len) {
459 char buf[5];
460 int n = (pub_len - i < 3 ? pub_len - i : 3);
461 base64_encode_atom(pub_blob + i, n, buf);
462 i += n;
463 buf[4] = '\0';
464 fputs(buf, fp);
465 if (++column >= 16) {
466 fputc('\n', fp);
467 column = 0;
468 }
469 }
470 if (column > 0)
471 fputc('\n', fp);
472
473 fprintf(fp, "---- END SSH2 PUBLIC KEY ----\n");
474 fclose(fp);
475 sfree(pub_blob);
476 return 1;
477 }
478
479 enum {
480 controlidstart = 100,
481 IDC_QUIT,
482 IDC_TITLE,
483 IDC_BOX_KEY,
484 IDC_NOKEY,
485 IDC_GENERATING,
486 IDC_PROGRESS,
487 IDC_PKSTATIC, IDC_KEYDISPLAY,
488 IDC_FPSTATIC, IDC_FINGERPRINT,
489 IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
490 IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
491 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT,
492 IDC_BOX_ACTIONS,
493 IDC_GENSTATIC, IDC_GENERATE,
494 IDC_LOADSTATIC, IDC_LOAD,
495 IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
496 IDC_BOX_PARAMS,
497 IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
498 IDC_BITSSTATIC, IDC_BITS,
499 IDC_ABOUT,
500 IDC_GIVEHELP,
501 IDC_IMPORT, IDC_EXPORT_OPENSSH, IDC_EXPORT_SSHCOM
502 };
503
504 static const int nokey_ids[] = { IDC_NOKEY, 0 };
505 static const int generating_ids[] = { 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
512 };
513
514 /*
515 * Small UI helper function to switch the state of the main dialog
516 * by enabling and disabling controls and menu items.
517 */
518 void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
519 {
520 int type;
521
522 switch (status) {
523 case 0: /* no key */
524 hidemany(hwnd, nokey_ids, FALSE);
525 hidemany(hwnd, generating_ids, TRUE);
526 hidemany(hwnd, gotkey_ids, TRUE);
527 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
528 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
529 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
530 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
531 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
532 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
533 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
534 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
535 EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
536 EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
537 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND);
538 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND);
539 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
540 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_ENABLED|MF_BYCOMMAND);
541 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND);
542 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
543 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH,
544 MF_GRAYED|MF_BYCOMMAND);
545 EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
546 MF_GRAYED|MF_BYCOMMAND);
547 break;
548 case 1: /* generating key */
549 hidemany(hwnd, nokey_ids, TRUE);
550 hidemany(hwnd, generating_ids, FALSE);
551 hidemany(hwnd, gotkey_ids, TRUE);
552 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0);
553 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0);
554 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
555 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
556 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0);
557 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
558 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0);
559 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
560 EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND);
561 EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
562 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND);
563 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_GRAYED|MF_BYCOMMAND);
564 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_GRAYED|MF_BYCOMMAND);
565 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_GRAYED|MF_BYCOMMAND);
566 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND);
567 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
568 EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH,
569 MF_GRAYED|MF_BYCOMMAND);
570 EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
571 MF_GRAYED|MF_BYCOMMAND);
572 break;
573 case 2:
574 hidemany(hwnd, nokey_ids, TRUE);
575 hidemany(hwnd, generating_ids, TRUE);
576 hidemany(hwnd, gotkey_ids, FALSE);
577 EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
578 EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
579 EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
580 EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
581 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
582 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
583 EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
584 EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
585 EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
586 EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND);
587 EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_ENABLED|MF_BYCOMMAND);
588 EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND);
589 EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
590 EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA,MF_ENABLED|MF_BYCOMMAND);
591 EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND);
592 EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
593 /*
594 * Enable export menu items if and only if the key type
595 * supports this kind of export.
596 */
597 type = state->ssh2 ? SSH_KEYTYPE_SSH2 : SSH_KEYTYPE_SSH1;
598 #define do_export_menuitem(x,y) \
599 EnableMenuItem(state->cvtmenu, x, MF_BYCOMMAND | \
600 (import_target_type(y)==type?MF_ENABLED:MF_GRAYED))
601 do_export_menuitem(IDC_EXPORT_OPENSSH, SSH_KEYTYPE_OPENSSH);
602 do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM);
603 #undef do_export_menuitem
604 break;
605 }
606 }
607
608 /*
609 * Dialog-box function for the main PuTTYgen dialog box.
610 */
611 static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
612 WPARAM wParam, LPARAM lParam)
613 {
614 static const char generating_msg[] =
615 "Please wait while a key is generated...";
616 static const char entropy_msg[] =
617 "Please generate some randomness by moving the mouse over the blank area.";
618 struct MainDlgState *state;
619
620 switch (msg) {
621 case WM_INITDIALOG:
622 if (help_path)
623 SetWindowLong(hwnd, GWL_EXSTYLE,
624 GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_CONTEXTHELP);
625 else {
626 /*
627 * If we add a Help button, this is where we destroy it
628 * if the help file isn't present.
629 */
630 }
631 requested_help = FALSE;
632
633 state = smalloc(sizeof(*state));
634 state->generation_thread_exists = FALSE;
635 state->collecting_entropy = FALSE;
636 state->entropy = NULL;
637 state->key_exists = FALSE;
638 SetWindowLong(hwnd, GWL_USERDATA, (LONG) state);
639 {
640 HMENU menu, menu1;
641
642 menu = CreateMenu();
643
644 menu1 = CreateMenu();
645 AppendMenu(menu1, MF_ENABLED, IDC_LOAD, "&Load private key");
646 AppendMenu(menu1, MF_ENABLED, IDC_SAVEPUB, "Save p&ublic key");
647 AppendMenu(menu1, MF_ENABLED, IDC_SAVE, "&Save private key");
648 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
649 AppendMenu(menu1, MF_ENABLED, IDC_QUIT, "E&xit");
650 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&File");
651 state->filemenu = menu1;
652
653 menu1 = CreateMenu();
654 AppendMenu(menu1, MF_ENABLED, IDC_GENERATE, "&Generate key pair");
655 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
656 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH1, "SSH&1 key (RSA)");
657 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2RSA, "SSH2 &RSA key");
658 AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2DSA, "SSH2 &DSA key");
659 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Key");
660 state->keymenu = menu1;
661
662 menu1 = CreateMenu();
663 AppendMenu(menu1, MF_ENABLED, IDC_IMPORT, "&Import key");
664 AppendMenu(menu1, MF_SEPARATOR, 0, 0);
665 AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH,
666 "Export &OpenSSH key");
667 AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM,
668 "Export &ssh.com key");
669 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1,
670 "&Conversions");
671 state->cvtmenu = menu1;
672
673 menu1 = CreateMenu();
674 AppendMenu(menu1, MF_ENABLED, IDC_ABOUT, "&About");
675 if (help_path)
676 AppendMenu(menu1, MF_ENABLED, IDC_GIVEHELP, "&Help");
677 AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Help");
678
679 SetMenu(hwnd, menu);
680 }
681
682 /*
683 * Centre the window.
684 */
685 { /* centre the window */
686 RECT rs, rd;
687 HWND hw;
688
689 hw = GetDesktopWindow();
690 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
691 MoveWindow(hwnd,
692 (rs.right + rs.left + rd.left - rd.right) / 2,
693 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
694 rd.right - rd.left, rd.bottom - rd.top, TRUE);
695 }
696
697 {
698 struct ctlpos cp, cp2;
699
700 /* Accelerators used: acglops1rbd */
701
702 ctlposinit(&cp, hwnd, 4, 4, 4);
703 beginbox(&cp, "Key", IDC_BOX_KEY);
704 cp2 = cp;
705 statictext(&cp2, "No key.", 1, IDC_NOKEY);
706 cp2 = cp;
707 statictext(&cp2, "", 1, IDC_GENERATING);
708 progressbar(&cp2, IDC_PROGRESS);
709 bigeditctrl(&cp,
710 "&Public key for pasting into authorized_keys file:",
711 IDC_PKSTATIC, IDC_KEYDISPLAY, 5);
712 SendDlgItemMessage(hwnd, IDC_KEYDISPLAY, EM_SETREADONLY, 1, 0);
713 staticedit(&cp, "Key fingerprint:", IDC_FPSTATIC,
714 IDC_FINGERPRINT, 75);
715 SendDlgItemMessage(hwnd, IDC_FINGERPRINT, EM_SETREADONLY, 1,
716 0);
717 staticedit(&cp, "Key &comment:", IDC_COMMENTSTATIC,
718 IDC_COMMENTEDIT, 75);
719 staticpassedit(&cp, "Key p&assphrase:", IDC_PASSPHRASE1STATIC,
720 IDC_PASSPHRASE1EDIT, 75);
721 staticpassedit(&cp, "C&onfirm passphrase:",
722 IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 75);
723 endbox(&cp);
724 beginbox(&cp, "Actions", IDC_BOX_ACTIONS);
725 staticbtn(&cp, "Generate a public/private key pair",
726 IDC_GENSTATIC, "&Generate", IDC_GENERATE);
727 staticbtn(&cp, "Load an existing private key file",
728 IDC_LOADSTATIC, "&Load", IDC_LOAD);
729 static2btn(&cp, "Save the generated key", IDC_SAVESTATIC,
730 "Save p&ublic key", IDC_SAVEPUB,
731 "&Save private key", IDC_SAVE);
732 endbox(&cp);
733 beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
734 radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 3,
735 "SSH&1 (RSA)", IDC_KEYSSH1,
736 "SSH2 &RSA", IDC_KEYSSH2RSA,
737 "SSH2 &DSA", IDC_KEYSSH2DSA, NULL);
738 staticedit(&cp, "Number of &bits in a generated key:",
739 IDC_BITSSTATIC, IDC_BITS, 20);
740 endbox(&cp);
741 }
742 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA, IDC_KEYSSH1);
743 CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA,
744 IDC_KEYSSH1, MF_BYCOMMAND);
745 SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE);
746
747 /*
748 * Initially, hide the progress bar and the key display,
749 * and show the no-key display. Also disable the Save
750 * buttons, because with no key we obviously can't save
751 * anything.
752 */
753 ui_set_state(hwnd, state, 0);
754
755 return 1;
756 case WM_MOUSEMOVE:
757 state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
758 if (state->collecting_entropy &&
759 state->entropy && state->entropy_got < state->entropy_required) {
760 state->entropy[state->entropy_got++] = lParam;
761 state->entropy[state->entropy_got++] = GetMessageTime();
762 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS,
763 state->entropy_got, 0);
764 if (state->entropy_got >= state->entropy_required) {
765 struct rsa_key_thread_params *params;
766 DWORD threadid;
767
768 /*
769 * Seed the entropy pool
770 */
771 random_add_heavynoise(state->entropy, state->entropy_size);
772 memset(state->entropy, 0, state->entropy_size);
773 sfree(state->entropy);
774 state->collecting_entropy = FALSE;
775
776 SetDlgItemText(hwnd, IDC_GENERATING, generating_msg);
777 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
778 MAKELPARAM(0, PROGRESSRANGE));
779 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
780
781 params = smalloc(sizeof(*params));
782 params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
783 params->dialog = hwnd;
784 params->keysize = state->keysize;
785 params->is_dsa = state->is_dsa;
786 params->key = &state->key;
787 params->dsskey = &state->dsskey;
788
789 if (!CreateThread(NULL, 0, generate_rsa_key_thread,
790 params, 0, &threadid)) {
791 MessageBox(hwnd, "Out of thread resources",
792 "Key generation error",
793 MB_OK | MB_ICONERROR);
794 sfree(params);
795 } else {
796 state->generation_thread_exists = TRUE;
797 }
798 }
799 }
800 break;
801 case WM_COMMAND:
802 switch (LOWORD(wParam)) {
803 case IDC_KEYSSH1:
804 case IDC_KEYSSH2RSA:
805 case IDC_KEYSSH2DSA:
806 {
807 state = (struct MainDlgState *)
808 GetWindowLong(hwnd, GWL_USERDATA);
809 if (!IsDlgButtonChecked(hwnd, LOWORD(wParam)))
810 CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA,
811 LOWORD(wParam));
812 CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA,
813 LOWORD(wParam), MF_BYCOMMAND);
814 }
815 break;
816 case IDC_QUIT:
817 PostMessage(hwnd, WM_CLOSE, 0, 0);
818 break;
819 case IDC_COMMENTEDIT:
820 if (HIWORD(wParam) == EN_CHANGE) {
821 state = (struct MainDlgState *)
822 GetWindowLong(hwnd, GWL_USERDATA);
823 if (state->key_exists) {
824 HWND editctl = GetDlgItem(hwnd, IDC_COMMENTEDIT);
825 int len = GetWindowTextLength(editctl);
826 if (*state->commentptr)
827 sfree(*state->commentptr);
828 *state->commentptr = smalloc(len + 1);
829 GetWindowText(editctl, *state->commentptr, len + 1);
830 if (state->ssh2) {
831 setupbigedit2(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
832 &state->ssh2key);
833 } else {
834 setupbigedit1(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
835 &state->key);
836 }
837 }
838 }
839 break;
840 case IDC_ABOUT:
841 EnableWindow(hwnd, 0);
842 DialogBox(hinst, MAKEINTRESOURCE(213), NULL, AboutProc);
843 EnableWindow(hwnd, 1);
844 SetActiveWindow(hwnd);
845 return 0;
846 case IDC_GIVEHELP:
847 if (HIWORD(wParam) == BN_CLICKED ||
848 HIWORD(wParam) == BN_DOUBLECLICKED) {
849 if (help_path) {
850 WinHelp(hwnd, help_path, HELP_COMMAND,
851 (DWORD)"JI(`',`puttygen.general')");
852 requested_help = TRUE;
853 }
854 }
855 return 0;
856 case IDC_GENERATE:
857 state =
858 (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
859 if (!state->generation_thread_exists) {
860 BOOL ok;
861 state->keysize = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE);
862 if (!ok)
863 state->keysize = DEFAULT_KEYSIZE;
864 /* If we ever introduce a new key type, check it here! */
865 state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
866 state->is_dsa = IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA);
867 if (state->keysize < 256) {
868 int ret = MessageBox(hwnd,
869 "PuTTYgen will not generate a key"
870 " smaller than 256 bits.\n"
871 "Key length reset to 256. Continue?",
872 "PuTTYgen Warning",
873 MB_ICONWARNING | MB_OKCANCEL);
874 if (ret != IDOK)
875 break;
876 state->keysize = 256;
877 SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
878 }
879 ui_set_state(hwnd, state, 1);
880 SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
881 state->key_exists = FALSE;
882 state->collecting_entropy = TRUE;
883
884 /*
885 * My brief statistical tests on mouse movements
886 * suggest that there are about 2.5 bits of
887 * randomness in the x position, 2.5 in the y
888 * position, and 1.7 in the message time, making
889 * 5.7 bits of unpredictability per mouse movement.
890 * However, other people have told me it's far less
891 * than that, so I'm going to be stupidly cautious
892 * and knock that down to a nice round 2. With this
893 * method, we require two words per mouse movement,
894 * so with 2 bits per mouse movement we expect 2
895 * bits every 2 words.
896 */
897 state->entropy_required = (state->keysize / 2) * 2;
898 state->entropy_got = 0;
899 state->entropy_size = (state->entropy_required *
900 sizeof(*state->entropy));
901 state->entropy = smalloc(state->entropy_size);
902
903 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
904 MAKELPARAM(0, state->entropy_required));
905 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
906 }
907 break;
908 case IDC_SAVE:
909 case IDC_EXPORT_OPENSSH:
910 case IDC_EXPORT_SSHCOM:
911 state =
912 (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
913 if (state->key_exists) {
914 char filename[FILENAME_MAX];
915 char passphrase[PASSPHRASE_MAXLEN];
916 char passphrase2[PASSPHRASE_MAXLEN];
917 int type, realtype;
918
919 if (state->ssh2)
920 realtype = SSH_KEYTYPE_SSH2;
921 else
922 realtype = SSH_KEYTYPE_SSH1;
923
924 if (LOWORD(wParam) == IDC_EXPORT_OPENSSH)
925 type = SSH_KEYTYPE_OPENSSH;
926 else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM)
927 type = SSH_KEYTYPE_SSHCOM;
928 else
929 type = realtype;
930
931 if (type != realtype &&
932 import_target_type(type) != realtype) {
933 char msg[256];
934 sprintf(msg, "Cannot export an SSH%d key in an SSH%d"
935 " format", (state->ssh2 ? 2 : 1),
936 (state->ssh2 ? 1 : 2));
937 MessageBox(hwnd, msg,
938 "PuTTYgen Error", MB_OK | MB_ICONERROR);
939 break;
940 }
941
942 GetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
943 passphrase, sizeof(passphrase));
944 GetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
945 passphrase2, sizeof(passphrase2));
946 if (strcmp(passphrase, passphrase2)) {
947 MessageBox(hwnd,
948 "The two passphrases given do not match.",
949 "PuTTYgen Error", MB_OK | MB_ICONERROR);
950 break;
951 }
952 if (!*passphrase) {
953 int ret;
954 ret = MessageBox(hwnd,
955 "Are you sure you want to save this key\n"
956 "without a passphrase to protect it?",
957 "PuTTYgen Warning",
958 MB_YESNO | MB_ICONWARNING);
959 if (ret != IDYES)
960 break;
961 }
962 if (prompt_keyfile(hwnd, "Save private key as:",
963 filename, 1)) {
964 int ret;
965 FILE *fp = fopen(filename, "r");
966 if (fp) {
967 char buffer[FILENAME_MAX + 80];
968 fclose(fp);
969 sprintf(buffer, "Overwrite existing file\n%.*s?",
970 FILENAME_MAX, filename);
971 ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
972 MB_YESNO | MB_ICONWARNING);
973 if (ret != IDYES)
974 break;
975 }
976
977 if (state->ssh2) {
978 if (type != realtype)
979 ret = export_ssh2(filename, type, &state->ssh2key,
980 *passphrase ? passphrase : NULL);
981 else
982 ret = ssh2_save_userkey(filename, &state->ssh2key,
983 *passphrase ? passphrase :
984 NULL);
985 } else {
986 if (type != realtype)
987 ret = export_ssh1(filename, type, &state->key,
988 *passphrase ? passphrase : NULL);
989 else
990 ret = saversakey(filename, &state->key,
991 *passphrase ? passphrase : NULL);
992 }
993 if (ret <= 0) {
994 MessageBox(hwnd, "Unable to save key file",
995 "PuTTYgen Error", MB_OK | MB_ICONERROR);
996 }
997 }
998 }
999 break;
1000 case IDC_SAVEPUB:
1001 state =
1002 (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
1003 if (state->key_exists) {
1004 char filename[FILENAME_MAX];
1005 if (prompt_keyfile(hwnd, "Save public key as:",
1006 filename, 1)) {
1007 int ret;
1008 FILE *fp = fopen(filename, "r");
1009 if (fp) {
1010 char buffer[FILENAME_MAX + 80];
1011 fclose(fp);
1012 sprintf(buffer, "Overwrite existing file\n%.*s?",
1013 FILENAME_MAX, filename);
1014 ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
1015 MB_YESNO | MB_ICONWARNING);
1016 if (ret != IDYES)
1017 break;
1018 }
1019 if (state->ssh2) {
1020 ret = save_ssh2_pubkey(filename, &state->ssh2key);
1021 } else {
1022 ret = save_ssh1_pubkey(filename, &state->key);
1023 }
1024 if (ret <= 0) {
1025 MessageBox(hwnd, "Unable to save key file",
1026 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1027 }
1028 }
1029 }
1030 break;
1031 case IDC_LOAD:
1032 case IDC_IMPORT:
1033 state =
1034 (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
1035 if (!state->generation_thread_exists) {
1036 char filename[FILENAME_MAX];
1037 if (prompt_keyfile(hwnd, "Load private key:", filename, 0)) {
1038 char passphrase[PASSPHRASE_MAXLEN];
1039 int needs_pass;
1040 int type, realtype;
1041 int ret;
1042 char *comment;
1043 struct PassphraseProcStruct pps;
1044 struct RSAKey newkey1;
1045 struct ssh2_userkey *newkey2 = NULL;
1046
1047 type = realtype = key_type(filename);
1048 if (type != SSH_KEYTYPE_SSH1 &&
1049 type != SSH_KEYTYPE_SSH2 &&
1050 !import_possible(type)) {
1051 char msg[256];
1052 sprintf(msg, "Couldn't load private key (%s)",
1053 key_type_to_str(type));
1054 MessageBox(NULL, msg,
1055 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1056 break;
1057 }
1058
1059 if (type != SSH_KEYTYPE_SSH1 &&
1060 type != SSH_KEYTYPE_SSH2) {
1061 realtype = type;
1062 type = import_target_type(type);
1063 }
1064
1065 comment = NULL;
1066 if (realtype == SSH_KEYTYPE_SSH1)
1067 needs_pass = rsakey_encrypted(filename, &comment);
1068 else if (realtype == SSH_KEYTYPE_SSH2)
1069 needs_pass =
1070 ssh2_userkey_encrypted(filename, &comment);
1071 else
1072 needs_pass = import_encrypted(filename, realtype,
1073 &comment);
1074 pps.passphrase = passphrase;
1075 pps.comment = comment;
1076 do {
1077 if (needs_pass) {
1078 int dlgret;
1079 dlgret = DialogBoxParam(hinst,
1080 MAKEINTRESOURCE(210),
1081 NULL, PassphraseProc,
1082 (LPARAM) & pps);
1083 if (!dlgret) {
1084 ret = -2;
1085 break;
1086 }
1087 } else
1088 *passphrase = '\0';
1089 if (type == SSH_KEYTYPE_SSH1) {
1090 if (realtype == type)
1091 ret = loadrsakey(filename, &newkey1,
1092 passphrase);
1093 else
1094 ret = import_ssh1(filename, realtype,
1095 &newkey1, passphrase);
1096 } else {
1097 if (realtype == type)
1098 newkey2 = ssh2_load_userkey(filename,
1099 passphrase);
1100 else
1101 newkey2 = import_ssh2(filename, realtype,
1102 passphrase);
1103 if (newkey2 == SSH2_WRONG_PASSPHRASE)
1104 ret = -1;
1105 else if (!newkey2)
1106 ret = 0;
1107 else
1108 ret = 1;
1109 }
1110 } while (ret == -1);
1111 if (comment)
1112 sfree(comment);
1113 if (ret == 0) {
1114 MessageBox(NULL, "Couldn't load private key.",
1115 "PuTTYgen Error", MB_OK | MB_ICONERROR);
1116 } else if (ret == 1) {
1117 /*
1118 * Now update the key controls with all the
1119 * key data.
1120 */
1121 {
1122 SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
1123 passphrase);
1124 SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
1125 passphrase);
1126 if (type == SSH_KEYTYPE_SSH1) {
1127 char buf[128];
1128 char *savecomment;
1129
1130 state->ssh2 = FALSE;
1131 state->commentptr = &state->key.comment;
1132 state->key = newkey1;
1133
1134 /*
1135 * Set the key fingerprint.
1136 */
1137 savecomment = state->key.comment;
1138 state->key.comment = NULL;
1139 rsa_fingerprint(buf, sizeof(buf),
1140 &state->key);
1141 state->key.comment = savecomment;
1142
1143 SetDlgItemText(hwnd, IDC_FINGERPRINT, buf);
1144 /*
1145 * Construct a decimal representation
1146 * of the key, for pasting into
1147 * .ssh/authorized_keys on a Unix box.
1148 */
1149 setupbigedit1(hwnd, IDC_KEYDISPLAY,
1150 IDC_PKSTATIC, &state->key);
1151 } else {
1152 char *fp;
1153 char *savecomment;
1154
1155 state->ssh2 = TRUE;
1156 state->commentptr =
1157 &state->ssh2key.comment;
1158 state->ssh2key = *newkey2; /* structure copy */
1159 sfree(newkey2);
1160
1161 savecomment = state->ssh2key.comment;
1162 state->ssh2key.comment = NULL;
1163 fp =
1164 state->ssh2key.alg->
1165 fingerprint(state->ssh2key.data);
1166 state->ssh2key.comment = savecomment;
1167
1168 SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
1169 sfree(fp);
1170
1171 setupbigedit2(hwnd, IDC_KEYDISPLAY,
1172 IDC_PKSTATIC, &state->ssh2key);
1173 }
1174 SetDlgItemText(hwnd, IDC_COMMENTEDIT,
1175 *state->commentptr);
1176 }
1177 /*
1178 * Finally, hide the progress bar and show
1179 * the key data.
1180 */
1181 ui_set_state(hwnd, state, 2);
1182 state->key_exists = TRUE;
1183
1184 /*
1185 * If the user has imported a foreign key
1186 * using the Load command, let them know.
1187 * If they've used the Import command, be
1188 * silent.
1189 */
1190 if (realtype != type && LOWORD(wParam) == IDC_LOAD) {
1191 char msg[512];
1192 sprintf(msg, "Successfully imported foreign key\n"
1193 "(%s).\n"
1194 "To use this key with PuTTY, you need to\n"
1195 "use the \"Save private key\" command to\n"
1196 "save it in PuTTY's own format.",
1197 key_type_to_str(realtype));
1198 MessageBox(NULL, msg, "PuTTYgen Notice",
1199 MB_OK | MB_ICONINFORMATION);
1200 }
1201 }
1202 }
1203 }
1204 break;
1205 }
1206 return 0;
1207 case WM_DONEKEY:
1208 state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
1209 state->generation_thread_exists = FALSE;
1210 state->key_exists = TRUE;
1211 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
1212 MAKELPARAM(0, PROGRESSRANGE));
1213 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0);
1214 if (state->ssh2) {
1215 if (state->is_dsa) {
1216 state->ssh2key.data = &state->dsskey;
1217 state->ssh2key.alg = &ssh_dss;
1218 } else {
1219 state->ssh2key.data = &state->key;
1220 state->ssh2key.alg = &ssh_rsa;
1221 }
1222 state->commentptr = &state->ssh2key.comment;
1223 } else {
1224 state->commentptr = &state->key.comment;
1225 }
1226 /*
1227 * Invent a comment for the key. We'll do this by including
1228 * the date in it. This will be so horrifyingly ugly that
1229 * the user will immediately want to change it, which is
1230 * what we want :-)
1231 */
1232 *state->commentptr = smalloc(30);
1233 {
1234 time_t t;
1235 struct tm *tm;
1236 time(&t);
1237 tm = localtime(&t);
1238 if (state->is_dsa)
1239 strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", tm);
1240 else
1241 strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", tm);
1242 }
1243
1244 /*
1245 * Now update the key controls with all the key data.
1246 */
1247 {
1248 char *savecomment;
1249 /*
1250 * Blank passphrase, initially. This isn't dangerous,
1251 * because we will warn (Are You Sure?) before allowing
1252 * the user to save an unprotected private key.
1253 */
1254 SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, "");
1255 SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, "");
1256 /*
1257 * Set the comment.
1258 */
1259 SetDlgItemText(hwnd, IDC_COMMENTEDIT, *state->commentptr);
1260 /*
1261 * Set the key fingerprint.
1262 */
1263 savecomment = *state->commentptr;
1264 *state->commentptr = NULL;
1265 if (state->ssh2) {
1266 char *fp;
1267 fp = state->ssh2key.alg->fingerprint(state->ssh2key.data);
1268 SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
1269 sfree(fp);
1270 } else {
1271 char buf[128];
1272 rsa_fingerprint(buf, sizeof(buf), &state->key);
1273 SetDlgItemText(hwnd, IDC_FINGERPRINT, buf);
1274 }
1275 *state->commentptr = savecomment;
1276 /*
1277 * Construct a decimal representation of the key, for
1278 * pasting into .ssh/authorized_keys or
1279 * .ssh/authorized_keys2 on a Unix box.
1280 */
1281 if (state->ssh2) {
1282 setupbigedit2(hwnd, IDC_KEYDISPLAY,
1283 IDC_PKSTATIC, &state->ssh2key);
1284 } else {
1285 setupbigedit1(hwnd, IDC_KEYDISPLAY,
1286 IDC_PKSTATIC, &state->key);
1287 }
1288 }
1289 /*
1290 * Finally, hide the progress bar and show the key data.
1291 */
1292 ui_set_state(hwnd, state, 2);
1293 break;
1294 case WM_HELP:
1295 if (help_path) {
1296 int id = ((LPHELPINFO)lParam)->iCtrlId;
1297 char *cmd = NULL;
1298 switch (id) {
1299 case IDC_GENERATING:
1300 case IDC_PROGRESS:
1301 case IDC_GENSTATIC:
1302 case IDC_GENERATE:
1303 cmd = "JI(`',`puttygen.generate')"; break;
1304 case IDC_PKSTATIC:
1305 case IDC_KEYDISPLAY:
1306 cmd = "JI(`',`puttygen.pastekey')"; break;
1307 case IDC_FPSTATIC:
1308 case IDC_FINGERPRINT:
1309 cmd = "JI(`',`puttygen.fingerprint')"; break;
1310 case IDC_COMMENTSTATIC:
1311 case IDC_COMMENTEDIT:
1312 cmd = "JI(`',`puttygen.comment')"; break;
1313 case IDC_PASSPHRASE1STATIC:
1314 case IDC_PASSPHRASE1EDIT:
1315 case IDC_PASSPHRASE2STATIC:
1316 case IDC_PASSPHRASE2EDIT:
1317 cmd = "JI(`',`puttygen.passphrase')"; break;
1318 case IDC_LOADSTATIC:
1319 case IDC_LOAD:
1320 cmd = "JI(`',`puttygen.load')"; break;
1321 case IDC_SAVESTATIC:
1322 case IDC_SAVE:
1323 cmd = "JI(`',`puttygen.savepriv')"; break;
1324 case IDC_SAVEPUB:
1325 cmd = "JI(`',`puttygen.savepub')"; break;
1326 case IDC_TYPESTATIC:
1327 case IDC_KEYSSH1:
1328 case IDC_KEYSSH2RSA:
1329 case IDC_KEYSSH2DSA:
1330 cmd = "JI(`',`puttygen.keytype')"; break;
1331 case IDC_BITSSTATIC:
1332 case IDC_BITS:
1333 cmd = "JI(`',`puttygen.bits')"; break;
1334 case IDC_IMPORT:
1335 case IDC_EXPORT_OPENSSH:
1336 case IDC_EXPORT_SSHCOM:
1337 cmd = "JI(`',`puttygen.conversions')"; break;
1338 }
1339 if (cmd) {
1340 WinHelp(hwnd, help_path, HELP_COMMAND, (DWORD)cmd);
1341 requested_help = TRUE;
1342 } else {
1343 MessageBeep(0);
1344 }
1345 }
1346 break;
1347 case WM_CLOSE:
1348 state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
1349 sfree(state);
1350 if (requested_help) {
1351 WinHelp(hwnd, help_path, HELP_QUIT, 0);
1352 requested_help = FALSE;
1353 }
1354 EndDialog(hwnd, 1);
1355 return 0;
1356 }
1357 return 0;
1358 }
1359
1360 void cleanup_exit(int code) { exit(code); }
1361
1362 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
1363 {
1364 InitCommonControls();
1365 hinst = inst;
1366
1367 /*
1368 * See if we can find our Help file.
1369 */
1370 {
1371 char b[2048], *p, *q, *r;
1372 FILE *fp;
1373 GetModuleFileName(NULL, b, sizeof(b) - 1);
1374 r = b;
1375 p = strrchr(b, '\\');
1376 if (p && p >= r) r = p+1;
1377 q = strrchr(b, ':');
1378 if (q && q >= r) r = q+1;
1379 strcpy(r, "putty.hlp");
1380 if ( (fp = fopen(b, "r")) != NULL) {
1381 help_path = dupstr(b);
1382 fclose(fp);
1383 } else
1384 help_path = NULL;
1385 }
1386
1387 random_init();
1388 return DialogBox(hinst, MAKEINTRESOURCE(201), NULL,
1389 MainDlgProc) != IDOK;
1390 }