#include <windows.h>
#include <commctrl.h>
#include <time.h>
-#ifndef NO_SECURITY
-#include <aclapi.h>
-#endif
#include <stdio.h>
+#include <stdlib.h>
#define PUTTY_DO_GLOBALS
#define WM_DONEKEY (WM_XUSER + 1)
-#define KEYSIZE 1024
-
-/*
- * TODO:
- * - have some means of verifying passphrase changes against typos
- * - prompt before overwriting an existing file
- * - check the return value from saversakey()
- * - test the generated keys for actual working-RSA-key-hood
- * - variable key size
- */
+#define DEFAULT_KEYSIZE 1024
/* ----------------------------------------------------------------------
* Progress report code. This is really horrible :-)
struct rsa_key_thread_params {
HWND progressbar; /* notify this with progress */
HWND dialog; /* notify this on completion */
+ int keysize; /* bits in key */
struct RSAKey *key;
struct RSAAux *aux;
};
struct progress prog;
prog.progbar = params->progressbar;
- rsa_generate(params->key, params->aux, KEYSIZE, progress_update, &prog);
+ rsa_generate(params->key, params->aux,
+ params->keysize, progress_update, &prog);
PostMessage(params->dialog, WM_DONEKEY, 0, 0);
- free(params);
+ sfree(params);
return 0;
}
int generation_thread_exists;
int key_exists;
int entropy_got, entropy_required, entropy_size;
+ int keysize;
unsigned *entropy;
struct RSAKey key;
struct RSAAux aux;
dec1 = bignum_decimal(key->exponent);
dec2 = bignum_decimal(key->modulus);
- buffer = malloc(strlen(dec1)+strlen(dec2)+
- strlen(key->comment)+30);
+ buffer = smalloc(strlen(dec1)+strlen(dec2)+
+ strlen(key->comment)+30);
sprintf(buffer, "%d %s %s %s",
ssh1_bignum_bitcount(key->modulus),
dec1, dec2, key->comment);
SetDlgItemText(hwnd, id, buffer);
- free(dec1);
- free(dec2);
- free(buffer);
+ sfree(dec1);
+ sfree(dec2);
+ sfree(buffer);
}
/*
enum {
controlidstart = 100,
IDC_TITLE,
- IDC_BOX_KEY, IDC_BOXT_KEY,
+ IDC_BOX_KEY,
IDC_NOKEY,
IDC_GENERATING,
IDC_PROGRESS,
IDC_PKSTATIC, IDC_KEYDISPLAY,
IDC_FPSTATIC, IDC_FINGERPRINT,
IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
- IDC_PASSPHRASESTATIC, IDC_PASSPHRASEEDIT,
- IDC_BOX_ACTIONS, IDC_BOXT_ACTIONS,
+ IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
+ IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT,
+ IDC_BOX_ACTIONS,
IDC_GENSTATIC, IDC_GENERATE,
IDC_LOADSTATIC, IDC_LOAD,
IDC_SAVESTATIC, IDC_SAVE,
+ IDC_BOX_PARAMS,
+ IDC_BITSSTATIC, IDC_BITS,
IDC_ABOUT,
};
static const int nokey_ids[] = { IDC_NOKEY, 0 };
IDC_PKSTATIC, IDC_KEYDISPLAY,
IDC_FPSTATIC, IDC_FINGERPRINT,
IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
- IDC_PASSPHRASESTATIC, IDC_PASSPHRASEEDIT, 0 };
+ IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
+ IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 0 };
static const char generating_msg[] =
"Please wait while a key is generated...";
static const char entropy_msg[] =
- "Please move the mouse in this window to generate randomness";
+ "Please generate some randomness by moving the mouse over the blank area.";
struct MainDlgState *state;
switch (msg) {
case WM_INITDIALOG:
- state = malloc(sizeof(*state));
+ state = smalloc(sizeof(*state));
state->generation_thread_exists = FALSE;
+ state->collecting_entropy = FALSE;
+ state->entropy = NULL;
state->key_exists = FALSE;
SetWindowLong(hwnd, GWL_USERDATA, (LONG)state);
{
struct ctlpos cp, cp2;
+ /* Accelerators used: acglops */
+
ctlposinit(&cp, hwnd, 10, 10, 10);
bartitle(&cp, "Public and private key generation for PuTTY",
IDC_TITLE);
beginbox(&cp, "Key",
- IDC_BOX_KEY, IDC_BOXT_KEY);
+ IDC_BOX_KEY);
cp2 = cp;
statictext(&cp2, "No key.", IDC_NOKEY);
cp2 = cp;
SendDlgItemMessage(hwnd, IDC_FINGERPRINT, EM_SETREADONLY, 1, 0);
staticedit(&cp, "Key &comment:", IDC_COMMENTSTATIC,
IDC_COMMENTEDIT, 70);
- staticpassedit(&cp, "Key p&assphrase:", IDC_PASSPHRASESTATIC,
- IDC_PASSPHRASEEDIT, 70);
+ staticpassedit(&cp, "Key p&assphrase:", IDC_PASSPHRASE1STATIC,
+ IDC_PASSPHRASE1EDIT, 70);
+ staticpassedit(&cp, "C&onfirm passphrase:", IDC_PASSPHRASE2STATIC,
+ IDC_PASSPHRASE2EDIT, 70);
endbox(&cp);
beginbox(&cp, "Actions",
- IDC_BOX_ACTIONS, IDC_BOXT_ACTIONS);
+ IDC_BOX_ACTIONS);
staticbtn(&cp, "Generate a public/private key pair",
IDC_GENSTATIC, "&Generate", IDC_GENERATE);
staticbtn(&cp, "Load an existing private key file",
staticbtn(&cp, "Save the generated key to a new file",
IDC_SAVESTATIC, "&Save", IDC_SAVE);
endbox(&cp);
+ beginbox(&cp, "Parameters",
+ IDC_BOX_PARAMS);
+ staticedit(&cp, "Number of &bits in a generated key:",
+ IDC_BITSSTATIC, IDC_BITS, 20);
+ endbox(&cp);
}
+ SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE);
+
/*
* Initially, hide the progress bar and the key display,
* and show the no-key display. Also disable the Save
return 1;
case WM_MOUSEMOVE:
state = (struct MainDlgState *)GetWindowLong(hwnd, GWL_USERDATA);
- if (state->collecting_entropy) {
+ if (state->collecting_entropy &&
+ state->entropy &&
+ state->entropy_got < state->entropy_required) {
state->entropy[state->entropy_got++] = lParam;
state->entropy[state->entropy_got++] = GetMessageTime();
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS,
*/
random_add_heavynoise(state->entropy, state->entropy_size);
memset(state->entropy, 0, state->entropy_size);
- free(state->entropy);
+ sfree(state->entropy);
+ state->collecting_entropy = FALSE;
SetDlgItemText(hwnd, IDC_GENERATING, generating_msg);
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
MAKELPARAM(0, PROGRESSRANGE));
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
- params = malloc(sizeof(*params));
+ params = smalloc(sizeof(*params));
params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
params->dialog = hwnd;
+ params->keysize = state->keysize;
params->key = &state->key;
params->aux = &state->aux;
MessageBox(hwnd, "Out of thread resources",
"Key generation error",
MB_OK | MB_ICONERROR);
- free(params);
+ sfree(params);
} else {
state->generation_thread_exists = TRUE;
- state->collecting_entropy = FALSE;
}
}
}
HWND editctl = GetDlgItem(hwnd, IDC_COMMENTEDIT);
int len = GetWindowTextLength(editctl);
if (state->key.comment)
- free(state->key.comment);
- state->key.comment = malloc(len+1);
+ sfree(state->key.comment);
+ state->key.comment = smalloc(len+1);
GetWindowText(editctl, state->key.comment, len+1);
}
}
case IDC_GENERATE:
state = (struct MainDlgState *)GetWindowLong(hwnd, GWL_USERDATA);
if (!state->generation_thread_exists) {
+ BOOL ok;
+ state->keysize = GetDlgItemInt(hwnd, IDC_BITS,
+ &ok, FALSE);
+ if (!ok) state->keysize = DEFAULT_KEYSIZE;
+ if (state->keysize < 256) {
+ int ret = MessageBox(hwnd,
+ "PuTTYgen will not generate a key"
+ " smaller than 256 bits.\n"
+ "Key length reset to 256. Continue?",
+ "PuTTYgen Warning",
+ MB_ICONWARNING | MB_OKCANCEL);
+ if (ret != IDOK)
+ break;
+ state->keysize = 256;
+ SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
+ }
hidemany(hwnd, nokey_ids, TRUE);
hidemany(hwnd, generating_ids, FALSE);
hidemany(hwnd, gotkey_ids, TRUE);
/*
* My brief statistical tests on mouse movements
- * suggest that there are about 5 bits of
- * randomness in the x position, 5 in the y
+ * suggest that there are about 2.5 bits of
+ * randomness in the x position, 2.5 in the y
* position, and 1.7 in the message time, making
- * 11.7 bits of unpredictability per mouse
- * movement. However, other people have told me
- * it's far less than that, so I'm going to be
- * stupidly cautious and knock that down to a nice
- * round 4.
+ * 5.7 bits of unpredictability per mouse movement.
+ * However, other people have told me it's far less
+ * than that, so I'm going to be stupidly cautious
+ * and knock that down to a nice round 2. With this
+ * method, we require two words per mouse movement,
+ * so with 2 bits per mouse movement we expect 2
+ * bits every 2 words.
*/
- state->entropy_required = (KEYSIZE / 4) * 2;
+ state->entropy_required = (state->keysize/2) * 2;
state->entropy_got = 0;
state->entropy_size = (state->entropy_required *
sizeof(*state->entropy));
- state->entropy = malloc(state->entropy_size);
+ state->entropy = smalloc(state->entropy_size);
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
MAKELPARAM(0, state->entropy_required));
if (state->key_exists) {
char filename[FILENAME_MAX];
char passphrase[PASSPHRASE_MAXLEN];
- GetDlgItemText(hwnd, IDC_PASSPHRASEEDIT,
- passphrase, sizeof(passphrase)-1);
+ char passphrase2[PASSPHRASE_MAXLEN];
+ GetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
+ passphrase, sizeof(passphrase));
+ GetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
+ passphrase2, sizeof(passphrase2));
+ if (strcmp(passphrase, passphrase2)) {
+ MessageBox(hwnd,
+ "The two passphrases given do not match.",
+ "PuTTYgen Error",
+ MB_OK | MB_ICONERROR);
+ break;
+ }
if (!*passphrase) {
int ret;
ret = MessageBox(hwnd,
}
if (prompt_keyfile(hwnd, "Save private key as:",
filename, 1)) {
- /* FIXME: prompt before overwriting */
- saversakey(filename, &state->key, &state->aux,
- *passphrase ? passphrase : NULL);
- /* FIXME: check return value */
+ int ret;
+ FILE *fp = fopen(filename, "r");
+ if (fp) {
+ char buffer[FILENAME_MAX+80];
+ fclose(fp);
+ sprintf(buffer, "Overwrite existing file\n%.*s?",
+ FILENAME_MAX, filename);
+ ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
+ MB_YESNO | MB_ICONWARNING);
+ if (ret != IDYES)
+ break;
+ }
+ ret = saversakey(filename, &state->key, &state->aux,
+ *passphrase ? passphrase : NULL);
+ if (ret <= 0) {
+ MessageBox(hwnd, "Unable to save key file",
+ "PuTTYgen Error",
+ MB_OK | MB_ICONERROR);
+ }
}
}
break;
ret = loadrsakey(filename, &newkey, &newaux,
passphrase);
} while (ret == -1);
- if (comment) free(comment);
+ if (comment) sfree(comment);
if (ret == 0) {
MessageBox(NULL, "Couldn't load private key.",
"PuTTYgen Error", MB_OK | MB_ICONERROR);
*/
{
char buf[128];
- SetDlgItemText(hwnd, IDC_PASSPHRASEEDIT,
+ SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
+ passphrase);
+ SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
passphrase);
SetDlgItemText(hwnd, IDC_COMMENTEDIT,
state->key.comment);
* the user will immediately want to change it, which is
* what we want :-)
*/
- state->key.comment = malloc(30);
+ state->key.comment = smalloc(30);
{
time_t t;
struct tm *tm;
* because we will warn (Are You Sure?) before allowing
* the user to save an unprotected private key.
*/
- SetDlgItemText(hwnd, IDC_PASSPHRASEEDIT, "");
+ SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, "");
+ SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, "");
/*
* Set the comment.
*/
break;
case WM_CLOSE:
state = (struct MainDlgState *)GetWindowLong(hwnd, GWL_USERDATA);
- free(state);
+ sfree(state);
EndDialog(hwnd, 1);
return 0;
}