return 0;
}
+typedef enum {RSA, DSA, ECDSA, ED25519} keytype;
+
/*
* Thread to generate a key.
*/
HWND progressbar; /* notify this with progress */
HWND dialog; /* notify this on completion */
int keysize; /* bits in key */
- int is_dsa;
- struct RSAKey *key;
- struct dss_key *dsskey;
+ keytype keytype;
+ union {
+ struct RSAKey *key;
+ struct dss_key *dsskey;
+ struct ec_key *eckey;
+ };
};
static DWORD WINAPI generate_rsa_key_thread(void *param)
{
progress_update(&prog, PROGFN_INITIALISE, 0, 0);
- if (params->is_dsa)
+ if (params->keytype == DSA)
dsa_generate(params->dsskey, params->keysize, progress_update, &prog);
+ else if (params->keytype == ECDSA)
+ ec_generate(params->eckey, params->keysize, progress_update, &prog);
+ else if (params->keytype == ED25519)
+ ec_edgenerate(params->eckey, params->keysize, progress_update, &prog);
else
rsa_generate(params->key, params->keysize, progress_update, &prog);
int key_exists;
int entropy_got, entropy_required, entropy_size;
int keysize;
- int ssh2, is_dsa;
+ int ssh2;
+ keytype keytype;
char **commentptr; /* points to key.comment or ssh2key.comment */
struct ssh2_userkey ssh2key;
unsigned *entropy;
- struct RSAKey key;
- struct dss_key dsskey;
+ union {
+ struct RSAKey key;
+ struct dss_key dsskey;
+ struct ec_key eckey;
+ };
HMENU filemenu, keymenu, cvtmenu;
};
static void setupbigedit1(HWND hwnd, int id, int idstatic, struct RSAKey *key)
{
- char *buffer;
- char *dec1, *dec2;
-
- dec1 = bignum_decimal(key->exponent);
- dec2 = bignum_decimal(key->modulus);
- buffer = dupprintf("%d %s %s %s", bignum_bitcount(key->modulus),
- dec1, dec2, key->comment);
+ char *buffer = ssh1_pubkey_str(key);
SetDlgItemText(hwnd, id, buffer);
SetDlgItemText(hwnd, idstatic,
"&Public key for pasting into authorized_keys file:");
- sfree(dec1);
- sfree(dec2);
sfree(buffer);
}
static void setupbigedit2(HWND hwnd, int id, int idstatic,
struct ssh2_userkey *key)
{
- unsigned char *pub_blob;
- char *buffer, *p;
- int pub_len;
- int i;
-
- pub_blob = key->alg->public_blob(key->data, &pub_len);
- buffer = snewn(strlen(key->alg->name) + 4 * ((pub_len + 2) / 3) +
- strlen(key->comment) + 3, char);
- strcpy(buffer, key->alg->name);
- p = buffer + strlen(buffer);
- *p++ = ' ';
- i = 0;
- while (i < pub_len) {
- int n = (pub_len - i < 3 ? pub_len - i : 3);
- base64_encode_atom(pub_blob + i, n, p);
- i += n;
- p += 4;
- }
- *p++ = ' ';
- strcpy(p, key->comment);
+ char *buffer = ssh2_pubkey_openssh_str(key);
SetDlgItemText(hwnd, id, buffer);
SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
"OpenSSH authorized_keys file:");
- sfree(pub_blob);
sfree(buffer);
}
-static int save_ssh1_pubkey(char *filename, struct RSAKey *key)
-{
- char *dec1, *dec2;
- FILE *fp;
-
- dec1 = bignum_decimal(key->exponent);
- dec2 = bignum_decimal(key->modulus);
- fp = fopen(filename, "wb");
- if (!fp)
- return 0;
- fprintf(fp, "%d %s %s %s\n",
- bignum_bitcount(key->modulus), dec1, dec2, key->comment);
- fclose(fp);
- sfree(dec1);
- sfree(dec2);
- return 1;
-}
-
/*
* Warn about the obsolescent key file format.
*/
IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
IDC_BOX_PARAMS,
IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
+ IDC_KEYSSH2ECDSA, IDC_KEYSSH2ED25519,
IDC_BITSSTATIC, IDC_BITS,
IDC_ABOUT,
IDC_GIVEHELP,
- IDC_IMPORT, IDC_EXPORT_OPENSSH, IDC_EXPORT_SSHCOM
+ IDC_IMPORT,
+ IDC_EXPORT_OPENSSH_AUTO, IDC_EXPORT_OPENSSH_NEW,
+ IDC_EXPORT_SSHCOM
};
static const int nokey_ids[] = { IDC_NOKEY, 0 };
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
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_BITS), 1);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND);
+ EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
+ MF_ENABLED|MF_BYCOMMAND);
+ EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
+ MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH,
+ EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
+ MF_GRAYED|MF_BYCOMMAND);
+ EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
MF_GRAYED|MF_BYCOMMAND);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0);
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_BITS), 0);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND);
+ EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
+ MF_GRAYED|MF_BYCOMMAND);
+ EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
+ MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH,
+ EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
+ MF_GRAYED|MF_BYCOMMAND);
+ EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
MF_GRAYED|MF_BYCOMMAND);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
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_BITS), 1);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA,MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND);
+ EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
+ MF_ENABLED|MF_BYCOMMAND);
+ EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
+ MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
/*
* Enable export menu items if and only if the key type
#define do_export_menuitem(x,y) \
EnableMenuItem(state->cvtmenu, x, MF_BYCOMMAND | \
(import_target_type(y)==type?MF_ENABLED:MF_GRAYED))
- do_export_menuitem(IDC_EXPORT_OPENSSH, SSH_KEYTYPE_OPENSSH);
+ do_export_menuitem(IDC_EXPORT_OPENSSH_AUTO, SSH_KEYTYPE_OPENSSH_AUTO);
+ do_export_menuitem(IDC_EXPORT_OPENSSH_NEW, SSH_KEYTYPE_OPENSSH_NEW);
do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM);
#undef do_export_menuitem
break;
AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH1, "SSH-&1 key (RSA)");
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(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Key");
state->keymenu = menu1;
menu1 = CreateMenu();
AppendMenu(menu1, MF_ENABLED, IDC_IMPORT, "&Import key");
AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH,
+ AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_AUTO,
"Export &OpenSSH key");
+ AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_NEW,
+ "Export &OpenSSH key (force new file format)");
AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM,
"Export &ssh.com key");
AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1,
{
struct ctlpos cp, cp2;
- /* Accelerators used: acglops1rbd */
+ /* Accelerators used: acglops1rbde */
ctlposinit(&cp, hwnd, 4, 4, 4);
beginbox(&cp, "Key", IDC_BOX_KEY);
"&Save private key", IDC_SAVE);
endbox(&cp);
beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
- radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 3,
+ radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 4,
"SSH-&1 (RSA)", IDC_KEYSSH1,
"SSH-2 &RSA", IDC_KEYSSH2RSA,
- "SSH-2 &DSA", IDC_KEYSSH2DSA, NULL);
+ "SSH-2 &DSA", IDC_KEYSSH2DSA,
+ "SSH-2 &ECDSA", IDC_KEYSSH2ECDSA,
+ "SSH-2 ED&25519", IDC_KEYSSH2ED25519, NULL);
staticedit(&cp, "Number of &bits in a generated key:",
IDC_BITSSTATIC, IDC_BITS, 20);
endbox(&cp);
}
- CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA, IDC_KEYSSH2RSA);
- CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA,
+ CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ECDSA, IDC_KEYSSH2RSA);
+ CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2ECDSA,
IDC_KEYSSH2RSA, MF_BYCOMMAND);
SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE);
/*
* Load a key file if one was provided on the command line.
*/
- if (cmdline_keyfile)
- load_key_file(hwnd, state, filename_from_str(cmdline_keyfile), 0);
+ if (cmdline_keyfile) {
+ Filename *fn = filename_from_str(cmdline_keyfile);
+ load_key_file(hwnd, state, fn, 0);
+ filename_free(fn);
+ }
return 1;
case WM_MOUSEMOVE:
params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
params->dialog = hwnd;
params->keysize = state->keysize;
- params->is_dsa = state->is_dsa;
+ params->keytype = state->keytype;
params->key = &state->key;
params->dsskey = &state->dsskey;
case IDC_KEYSSH1:
case IDC_KEYSSH2RSA:
case IDC_KEYSSH2DSA:
+ case IDC_KEYSSH2ECDSA:
+ case IDC_KEYSSH2ED25519:
{
state = (struct MainDlgState *)
GetWindowLongPtr(hwnd, GWLP_USERDATA);
LOWORD(wParam));
CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA,
LOWORD(wParam), MF_BYCOMMAND);
+ CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ECDSA,
+ LOWORD(wParam));
+ CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1,
+ IDC_KEYSSH2ECDSA,
+ LOWORD(wParam), MF_BYCOMMAND);
}
break;
case IDC_QUIT:
state->keysize = DEFAULT_KEYSIZE;
/* If we ever introduce a new key type, check it here! */
state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
- state->is_dsa = IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA);
+ 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;
+ }
if (state->keysize < 256) {
int ret = MessageBox(hwnd,
"PuTTYgen will not generate a key"
state->keysize = 256;
SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
}
+ if (state->keytype == ECDSA && !(state->keysize == 256 ||
+ state->keysize == 384 ||
+ state->keysize == 521)) {
+ int ret = MessageBox(hwnd,
+ "Only 256, 384 and 521 bit elliptic"
+ " curves are supported.\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);
+ }
+ if (state->keytype == ED25519 && state->keysize != 256) {
+ int ret = MessageBox(hwnd,
+ "Only 256 bit Edwards elliptic"
+ " curves are supported.\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);
+ }
ui_set_state(hwnd, state, 1);
SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
state->key_exists = FALSE;
}
break;
case IDC_SAVE:
- case IDC_EXPORT_OPENSSH:
+ case IDC_EXPORT_OPENSSH_AUTO:
+ case IDC_EXPORT_OPENSSH_NEW:
case IDC_EXPORT_SSHCOM:
if (HIWORD(wParam) != BN_CLICKED)
break;
else
realtype = SSH_KEYTYPE_SSH1;
- if (LOWORD(wParam) == IDC_EXPORT_OPENSSH)
- type = SSH_KEYTYPE_OPENSSH;
+ if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_AUTO)
+ type = SSH_KEYTYPE_OPENSSH_AUTO;
+ else if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_NEW)
+ type = SSH_KEYTYPE_OPENSSH_NEW;
else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM)
type = SSH_KEYTYPE_SSHCOM;
else
if (ret != IDYES)
break;
}
- if (state->ssh2) {
- ret = save_ssh2_pubkey(filename, &state->ssh2key);
- } else {
- ret = save_ssh1_pubkey(filename, &state->key);
- }
- if (ret <= 0) {
- MessageBox(hwnd, "Unable to save key file",
- "PuTTYgen Error", MB_OK | MB_ICONERROR);
- }
+ fp = fopen(filename, "w");
+ if (!fp) {
+ MessageBox(hwnd, "Unable to open key file",
+ "PuTTYgen Error", MB_OK | MB_ICONERROR);
+ } else {
+ if (state->ssh2) {
+ int bloblen;
+ unsigned char *blob;
+ blob = state->ssh2key.alg->public_blob
+ (state->ssh2key.data, &bloblen);
+ ssh2_write_pubkey(fp, state->ssh2key.comment,
+ blob, bloblen,
+ SSH_KEYTYPE_SSH2_PUBLIC_RFC4716);
+ } else {
+ ssh1_write_pubkey(fp, &state->key);
+ }
+ if (fclose(fp) < 0) {
+ MessageBox(hwnd, "Unable to save key file",
+ "PuTTYgen Error", MB_OK | MB_ICONERROR);
+ }
+ }
}
}
break;
if (!state->generation_thread_exists) {
char filename[FILENAME_MAX];
if (prompt_keyfile(hwnd, "Load private key:",
- filename, 0, LOWORD(wParam)==IDC_LOAD))
- load_key_file(hwnd, state, filename_from_str(filename),
- LOWORD(wParam) != IDC_LOAD);
+ filename, 0, LOWORD(wParam)==IDC_LOAD)) {
+ Filename *fn = filename_from_str(filename);
+ load_key_file(hwnd, state, fn, LOWORD(wParam) != IDC_LOAD);
+ filename_free(fn);
+ }
}
break;
}
MAKELPARAM(0, PROGRESSRANGE));
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0);
if (state->ssh2) {
- if (state->is_dsa) {
+ if (state->keytype == DSA) {
state->ssh2key.data = &state->dsskey;
state->ssh2key.alg = &ssh_dss;
+ } else if (state->keytype == ECDSA) {
+ state->ssh2key.data = &state->eckey;
+ if (state->eckey.publicKey.curve->fieldBits == 256)
+ state->ssh2key.alg = &ssh_ecdsa_nistp256;
+ else if (state->eckey.publicKey.curve->fieldBits == 384)
+ state->ssh2key.alg = &ssh_ecdsa_nistp384;
+ else
+ state->ssh2key.alg = &ssh_ecdsa_nistp521;
+ } else if (state->keytype == ED25519) {
+ state->ssh2key.data = &state->eckey;
+ state->ssh2key.alg = &ssh_ecdsa_ed25519;
} else {
state->ssh2key.data = &state->key;
state->ssh2key.alg = &ssh_rsa;
{
struct tm tm;
tm = ltime();
- if (state->is_dsa)
+ if (state->keytype == DSA)
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
strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", &tm);
}
case IDC_KEYSSH1:
case IDC_KEYSSH2RSA:
case IDC_KEYSSH2DSA:
+ case IDC_KEYSSH2ECDSA:
+ case IDC_KEYSSH2ED25519:
topic = WINHELP_CTX_puttygen_keytype; break;
case IDC_BITSSTATIC:
case IDC_BITS:
topic = WINHELP_CTX_puttygen_bits; break;
case IDC_IMPORT:
- case IDC_EXPORT_OPENSSH:
+ case IDC_EXPORT_OPENSSH_AUTO:
+ case IDC_EXPORT_OPENSSH_NEW:
case IDC_EXPORT_SSHCOM:
topic = WINHELP_CTX_puttygen_conversions; break;
}