1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-24 16:52:24 +00:00

PuTTYgen: prepare for more general EdDSA.

In the Windows GUI, all the controls that were previously named or
labelled Ed25519 are now labelled EdDSA, and when you select that
top-level key type, there's a dropdown for the specific curve (just
like for ECDSA), whose only current value is Ed25519.

In command-line PuTTYgen, you can say '-t eddsa' and give a number of
bits, just like '-t ecdsa'. You can also still say '-t ed25519', for
backwards compatibility.

Also in command-line PuTTYgen, I've reworked the error messages if you
give a number of bits that doesn't correspond to a known elliptic
curve. Now the messages are generated by consulting the list of
curves, so that that list has to be updated by hand in one fewer
place.
This commit is contained in:
Simon Tatham 2020-03-02 07:05:19 +00:00
parent 5f3d79332e
commit 9334eb3ff0
2 changed files with 123 additions and 60 deletions

View File

@ -114,8 +114,9 @@ void help(void)
printf("PuTTYgen: key generator and converter for the PuTTY tools\n"
"%s\n", ver);
usage(false);
printf(" -t specify key type when generating (ed25519, ecdsa, rsa, "
"dsa, rsa1)\n"
printf(" -t specify key type when generating:\n"
" eddsa, ecdsa, rsa, dsa, rsa1 use with -b\n"
" ed25519 special case of eddsa\n"
" -b specify number of bits when generating key\n"
" -C change or specify key comment\n"
" -P change key passphrase\n"
@ -202,7 +203,7 @@ int main(int argc, char **argv)
Filename *infilename = NULL, *outfilename = NULL;
LoadedFile *infile_lf = NULL;
BinarySource *infile_bs = NULL;
enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA, ED25519 } keytype = NOKEYGEN;
enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA, EDDSA } keytype = NOKEYGEN;
char *outfile = NULL, *outfiletmp = NULL;
enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH_AUTO,
OPENSSH_NEW, SSHCOM, TEXT } outtype = PRIVATE;
@ -430,8 +431,10 @@ int main(int argc, char **argv)
keytype = DSA, sshver = 2;
else if (!strcmp(p, "ecdsa"))
keytype = ECDSA, sshver = 2;
else if (!strcmp(p, "eddsa"))
keytype = EDDSA, sshver = 2;
else if (!strcmp(p, "ed25519"))
keytype = ED25519, sshver = 2;
keytype = EDDSA, bits = 255, sshver = 2;
else {
fprintf(stderr,
"puttygen: unknown key type `%s'\n", p);
@ -505,7 +508,7 @@ int main(int argc, char **argv)
case ECDSA:
bits = 384;
break;
case ED25519:
case EDDSA:
bits = 255;
break;
default:
@ -514,14 +517,29 @@ int main(int argc, char **argv)
}
}
if (keytype == ECDSA && (bits != 256 && bits != 384 && bits != 521)) {
fprintf(stderr, "puttygen: invalid bits for ECDSA, choose 256, 384 or 521\n");
if (keytype == ECDSA || keytype == EDDSA) {
const char *name = (keytype == ECDSA ? "ECDSA" : "EdDSA");
const int *valid_lengths = (keytype == ECDSA ? ec_nist_curve_lengths :
ec_ed_curve_lengths);
size_t n_lengths = (keytype == ECDSA ? n_ec_nist_curve_lengths :
n_ec_ed_curve_lengths);
bool (*alg_and_curve_by_bits)(int, const struct ec_curve **,
const ssh_keyalg **) =
(keytype == ECDSA ? ec_nist_alg_and_curve_by_bits :
ec_ed_alg_and_curve_by_bits);
const struct ec_curve *curve;
const ssh_keyalg *alg;
if (!alg_and_curve_by_bits(bits, &curve, &alg)) {
fprintf(stderr, "puttygen: invalid bits for %s, choose", name);
for (size_t i = 0; i < n_lengths; i++)
fprintf(stderr, "%s%d", (i == 0 ? " " :
i == n_lengths-1 ? " or " : ", "),
valid_lengths[i]);
fputc('\n', stderr);
errs = true;
}
if (keytype == ED25519 && (bits != 255) && (bits != 256)) {
fprintf(stderr, "puttygen: invalid bits for ED25519, choose 255\n");
errs = true;
}
if (keytype == RSA2 || keytype == RSA1 || keytype == DSA) {
@ -715,8 +733,10 @@ int main(int argc, char **argv)
strftime(default_comment, 30, "dsa-key-%Y%m%d", &tm);
else if (keytype == ECDSA)
strftime(default_comment, 30, "ecdsa-key-%Y%m%d", &tm);
else if (keytype == ED25519)
else if (keytype == EDDSA && bits == 255)
strftime(default_comment, 30, "ed25519-key-%Y%m%d", &tm);
else if (keytype == EDDSA)
strftime(default_comment, 30, "eddsa-key-%Y%m%d", &tm);
else
strftime(default_comment, 30, "rsa-key-%Y%m%d", &tm);
@ -745,7 +765,7 @@ int main(int argc, char **argv)
ssh2key = snew(ssh2_userkey);
ssh2key->key = &ek->sshk;
ssh1key = NULL;
} else if (keytype == ED25519) {
} else if (keytype == EDDSA) {
struct eddsa_key *ek = snew(struct eddsa_key);
eddsa_generate(ek, bits);
ssh2key = snew(ssh2_userkey);

View File

@ -22,7 +22,8 @@
#define WM_DONEKEY (WM_APP + 1)
#define DEFAULT_KEY_BITS 2048
#define DEFAULT_CURVE_INDEX 0
#define DEFAULT_ECCURVE_INDEX 0
#define DEFAULT_EDCURVE_INDEX 0
static char *cmdline_keyfile = NULL;
@ -382,7 +383,7 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg,
return 0;
}
typedef enum {RSA, DSA, ECDSA, ED25519} keytype;
typedef enum {RSA, DSA, ECDSA, EDDSA} keytype;
/*
* Thread to generate a key.
@ -416,8 +417,8 @@ static DWORD WINAPI generate_key_thread(void *param)
dsa_generate(params->dsskey, params->key_bits, pgc, &prog.rec);
else if (params->keytype == ECDSA)
ecdsa_generate(params->eckey, params->curve_bits);
else if (params->keytype == ED25519)
eddsa_generate(params->edkey, 255);
else if (params->keytype == EDDSA)
eddsa_generate(params->edkey, params->curve_bits);
else
rsa_generate(params->key, params->key_bits, pgc, &prog.rec);
@ -515,10 +516,11 @@ enum {
IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
IDC_BOX_PARAMS,
IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
IDC_KEYSSH2ECDSA, IDC_KEYSSH2ED25519,
IDC_KEYSSH2ECDSA, IDC_KEYSSH2EDDSA,
IDC_PRIMEGEN_PROB, IDC_PRIMEGEN_MAURER_SIMPLE, IDC_PRIMEGEN_MAURER_COMPLEX,
IDC_BITSSTATIC, IDC_BITS,
IDC_CURVESTATIC, IDC_CURVE,
IDC_ECCURVESTATIC, IDC_ECCURVE,
IDC_EDCURVESTATIC, IDC_EDCURVE,
IDC_NOTHINGSTATIC,
IDC_ABOUT,
IDC_GIVEHELP,
@ -558,7 +560,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2EDDSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
@ -569,7 +571,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
EnableMenuItem(state->keymenu, IDC_KEYSSH2EDDSA,
MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
@ -591,7 +593,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 0);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 0);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2EDDSA), 0);
EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
@ -602,7 +604,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
EnableMenuItem(state->keymenu, IDC_KEYSSH2EDDSA,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
@ -624,7 +626,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2EDDSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND);
@ -635,7 +637,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
EnableMenuItem(state->keymenu, IDC_KEYSSH2EDDSA,
MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
/*
@ -661,12 +663,15 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
*/
void ui_update_key_type_ctrls(HWND hwnd)
{
enum { BITS, CURVE, NOTHING } which;
enum { BITS, ECCURVE, EDCURVE, NOTHING } which;
static const int bits_ids[] = {
IDC_BITSSTATIC, IDC_BITS, 0
};
static const int curve_ids[] = {
IDC_CURVESTATIC, IDC_CURVE, 0
static const int eccurve_ids[] = {
IDC_ECCURVESTATIC, IDC_ECCURVE, 0
};
static const int edcurve_ids[] = {
IDC_EDCURVESTATIC, IDC_EDCURVE, 0
};
static const int nothing_ids[] = {
IDC_NOTHINGSTATIC, 0
@ -677,20 +682,25 @@ void ui_update_key_type_ctrls(HWND hwnd)
IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA)) {
which = BITS;
} else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) {
which = CURVE;
which = ECCURVE;
} else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2EDDSA)) {
which = EDCURVE;
} else {
/* ED25519 implicitly only supports one curve */
/* Currently not used since Ed25519 stopped being the only
* thing in its class, but I'll keep it here in case it comes
* in useful again */
which = NOTHING;
}
hidemany(hwnd, bits_ids, which != BITS);
hidemany(hwnd, curve_ids, which != CURVE);
hidemany(hwnd, eccurve_ids, which != ECCURVE);
hidemany(hwnd, edcurve_ids, which != EDCURVE);
hidemany(hwnd, nothing_ids, which != NOTHING);
}
void ui_set_key_type(HWND hwnd, struct MainDlgState *state, int button)
{
CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ED25519, button);
CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2ED25519,
CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2EDDSA, button);
CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2EDDSA,
button, MF_BYCOMMAND);
ui_update_key_type_ctrls(hwnd);
}
@ -967,7 +977,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2RSA, "SSH-2 &RSA key");
AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2DSA, "SSH-2 &DSA key");
AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ECDSA, "SSH-2 &ECDSA key");
AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ED25519, "SSH-2 Ed&25519 key");
AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2EDDSA, "SSH-2 EdD&SA key");
AppendMenu(menu1, MF_SEPARATOR, 0, 0);
AppendMenu(menu1, MF_ENABLED, IDC_PRIMEGEN_PROB,
"Use probable primes (fast)");
@ -1057,7 +1067,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
"&RSA", IDC_KEYSSH2RSA,
"&DSA", IDC_KEYSSH2DSA,
"&ECDSA", IDC_KEYSSH2ECDSA,
"Ed&25519", IDC_KEYSSH2ED25519,
"EdD&SA", IDC_KEYSSH2EDDSA,
"SSH-&1 (RSA)", IDC_KEYSSH1,
NULL);
cp2 = cp;
@ -1066,8 +1076,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
ymax = cp2.ypos;
cp2 = cp;
staticddl(&cp2, "Cur&ve to use for generating this key:",
IDC_CURVESTATIC, IDC_CURVE, 20);
SendDlgItemMessage(hwnd, IDC_CURVE, CB_RESETCONTENT, 0, 0);
IDC_ECCURVESTATIC, IDC_ECCURVE, 30);
SendDlgItemMessage(hwnd, IDC_ECCURVE, CB_RESETCONTENT, 0, 0);
{
int i, bits;
const struct ec_curve *curve;
@ -1076,12 +1086,32 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
for (i = 0; i < n_ec_nist_curve_lengths; i++) {
bits = ec_nist_curve_lengths[i];
ec_nist_alg_and_curve_by_bits(bits, &curve, &alg);
SendDlgItemMessage(hwnd, IDC_CURVE, CB_ADDSTRING, 0,
SendDlgItemMessage(hwnd, IDC_ECCURVE, CB_ADDSTRING, 0,
(LPARAM)curve->textname);
}
}
ymax = ymax > cp2.ypos ? ymax : cp2.ypos;
cp2 = cp;
staticddl(&cp2, "Cur&ve to use for generating this key:",
IDC_EDCURVESTATIC, IDC_EDCURVE, 30);
SendDlgItemMessage(hwnd, IDC_EDCURVE, CB_RESETCONTENT, 0, 0);
{
int i, bits;
const struct ec_curve *curve;
const ssh_keyalg *alg;
for (i = 0; i < n_ec_ed_curve_lengths; i++) {
bits = ec_ed_curve_lengths[i];
ec_ed_alg_and_curve_by_bits(bits, &curve, &alg);
char *desc = dupprintf("%s (%d bits)",
curve->textname, bits);
SendDlgItemMessage(hwnd, IDC_EDCURVE, CB_ADDSTRING, 0,
(LPARAM)desc);
sfree(desc);
}
}
ymax = ymax > cp2.ypos ? ymax : cp2.ypos;
cp2 = cp;
statictext(&cp2, "(nothing to configure for this key type)",
1, IDC_NOTHINGSTATIC);
ymax = ymax > cp2.ypos ? ymax : cp2.ypos;
@ -1091,8 +1121,10 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
ui_set_key_type(hwnd, state, IDC_KEYSSH2RSA);
ui_set_primepolicy(hwnd, state, IDC_PRIMEGEN_PROB);
SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEY_BITS, false);
SendDlgItemMessage(hwnd, IDC_CURVE, CB_SETCURSEL,
DEFAULT_CURVE_INDEX, 0);
SendDlgItemMessage(hwnd, IDC_ECCURVE, CB_SETCURSEL,
DEFAULT_ECCURVE_INDEX, 0);
SendDlgItemMessage(hwnd, IDC_EDCURVE, CB_SETCURSEL,
DEFAULT_EDCURVE_INDEX, 0);
/*
* Initially, hide the progress bar and the key display,
@ -1140,7 +1172,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
case IDC_KEYSSH2RSA:
case IDC_KEYSSH2DSA:
case IDC_KEYSSH2ECDSA:
case IDC_KEYSSH2ED25519: {
case IDC_KEYSSH2EDDSA: {
state = (struct MainDlgState *)
GetWindowLongPtr(hwnd, GWLP_USERDATA);
ui_set_key_type(hwnd, state, LOWORD(wParam));
@ -1200,25 +1232,36 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
unsigned raw_entropy_required;
unsigned char *raw_entropy_buf;
BOOL ok;
state->key_bits = GetDlgItemInt(hwnd, IDC_BITS, &ok, false);
if (!ok)
state->key_bits = DEFAULT_KEY_BITS;
{
int curveindex = SendDlgItemMessage(hwnd, IDC_CURVE,
state->ssh2 = true;
if (IsDlgButtonChecked(hwnd, IDC_KEYSSH1)) {
state->ssh2 = false;
state->keytype = RSA;
} else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2RSA)) {
state->keytype = RSA;
} else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA)) {
state->keytype = DSA;
} else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) {
state->keytype = ECDSA;
int curveindex = SendDlgItemMessage(hwnd, IDC_ECCURVE,
CB_GETCURSEL, 0, 0);
assert(curveindex >= 0);
assert(curveindex < n_ec_nist_curve_lengths);
state->curve_bits = ec_nist_curve_lengths[curveindex];
}
/* If we ever introduce a new key type, check it here! */
state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
state->keytype = RSA;
if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA)) {
state->keytype = DSA;
} else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) {
state->keytype = ECDSA;
} else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ED25519)) {
state->keytype = ED25519;
} else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2EDDSA)) {
state->keytype = EDDSA;
int curveindex = SendDlgItemMessage(hwnd, IDC_EDCURVE,
CB_GETCURSEL, 0, 0);
assert(curveindex >= 0);
assert(curveindex < n_ec_ed_curve_lengths);
state->curve_bits = ec_ed_curve_lengths[curveindex];
} else {
/* Somehow, no button was checked */
break;
}
if ((state->keytype == RSA || state->keytype == DSA) &&
@ -1248,10 +1291,10 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
if (state->keytype == RSA || state->keytype == DSA)
raw_entropy_required = (state->key_bits / 2) * 2;
else if (state->keytype == ECDSA)
else if (state->keytype == ECDSA || state->keytype == EDDSA)
raw_entropy_required = (state->curve_bits / 2) * 2;
else
raw_entropy_required = 256;
unreachable("we must have initialised keytype by now");
/* Bound the entropy collection above by the amount of
* data we can actually fit into the PRNG. Any more
@ -1493,7 +1536,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
state->ssh2key.key = &state->dsskey.sshk;
} else if (state->keytype == ECDSA) {
state->ssh2key.key = &state->eckey.sshk;
} else if (state->keytype == ED25519) {
} else if (state->keytype == EDDSA) {
state->ssh2key.key = &state->edkey.sshk;
} else {
state->ssh2key.key = &state->key.sshk;
@ -1516,8 +1559,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", &tm);
else if (state->keytype == ECDSA)
strftime(*state->commentptr, 30, "ecdsa-key-%Y%m%d", &tm);
else if (state->keytype == ED25519)
strftime(*state->commentptr, 30, "ed25519-key-%Y%m%d", &tm);
else if (state->keytype == EDDSA)
strftime(*state->commentptr, 30, "eddsa-key-%Y%m%d", &tm);
else
strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", &tm);
}
@ -1604,7 +1647,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
case IDC_KEYSSH2RSA:
case IDC_KEYSSH2DSA:
case IDC_KEYSSH2ECDSA:
case IDC_KEYSSH2ED25519:
case IDC_KEYSSH2EDDSA:
topic = WINHELP_CTX_puttygen_keytype; break;
case IDC_BITSSTATIC:
case IDC_BITS: