1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Support public keys using the "ssh-ed25519" method.

This introduces a third system of elliptic curve representation and
arithmetic, namely Edwards form.
This commit is contained in:
Chris Staite 2015-05-09 15:02:54 +01:00 committed by Simon Tatham
parent 541abf9258
commit 76a4b576e5
7 changed files with 1221 additions and 83 deletions

View File

@ -269,7 +269,7 @@ int main(int argc, char **argv)
{
char *infile = NULL;
Filename *infilename = NULL, *outfilename = NULL;
enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA } keytype = NOKEYGEN;
enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA, ED25519 } keytype = NOKEYGEN;
char *outfile = NULL, *outfiletmp = NULL;
enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH_PEM,
OPENSSH_NEW, SSHCOM } outtype = PRIVATE;
@ -444,6 +444,8 @@ int main(int argc, char **argv)
keytype = DSA, sshver = 2;
else if (!strcmp(p, "ecdsa"))
keytype = ECDSA, sshver = 2;
else if (!strcmp(p, "ed25519"))
keytype = ED25519, sshver = 2;
else {
fprintf(stderr,
"puttygen: unknown key type `%s'\n", p);
@ -516,6 +518,9 @@ int main(int argc, char **argv)
case ECDSA:
bits = 384;
break;
case ED25519:
bits = 256;
break;
default:
bits = 2048;
break;
@ -527,6 +532,11 @@ int main(int argc, char **argv)
errs = TRUE;
}
if (keytype == ED25519 && (bits != 256)) {
fprintf(stderr, "puttygen: invalid bits for ED25519, choose 256\n");
errs = TRUE;
}
if (errs)
return 1;
@ -702,6 +712,8 @@ 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)
strftime(default_comment, 30, "ed25519-key-%Y%m%d", &tm);
else
strftime(default_comment, 30, "rsa-key-%Y%m%d", &tm);
@ -736,6 +748,13 @@ int main(int argc, char **argv)
ssh2key->alg = &ssh_ecdsa_nistp521;
}
ssh1key = NULL;
} else if (keytype == ED25519) {
struct ec_key *ec = snew(struct ec_key);
ec_edgenerate(ec, bits, progressfn, &prog);
ssh2key = snew(struct ssh2_userkey);
ssh2key->data = ec;
ssh2key->alg = &ssh_ecdsa_ed25519;
ssh1key = NULL;
} else {
struct RSAKey *rsakey = snew(struct RSAKey);
rsa_generate(rsakey, bits, progressfn, &prog);

1
ssh.c
View File

@ -406,6 +406,7 @@ static void ssh_channel_destroy(struct ssh_channel *c);
#define OUR_V2_PACKETLIMIT 0x9000UL
const static struct ssh_signkey *hostkey_algs[] = {
&ssh_ecdsa_ed25519,
&ssh_ecdsa_nistp256, &ssh_ecdsa_nistp384, &ssh_ecdsa_nistp521,
&ssh_rsa, &ssh_dss
};

13
ssh.h
View File

@ -124,13 +124,21 @@ struct ec_mcurve
struct ec_point G;
};
/* Edwards form curve */
struct ec_ecurve
{
Bignum l, d;
struct ec_point B;
};
struct ec_curve {
enum { EC_WEIERSTRASS, EC_MONTGOMERY } type;
enum { EC_WEIERSTRASS, EC_MONTGOMERY, EC_EDWARDS } type;
unsigned int fieldBits;
Bignum p;
union {
struct ec_wcurve w;
struct ec_mcurve m;
struct ec_ecurve e;
};
};
@ -421,6 +429,7 @@ extern const struct ssh_kexes ssh_rsa_kex;
extern const struct ssh_kexes ssh_ecdh_kex;
extern const struct ssh_signkey ssh_dss;
extern const struct ssh_signkey ssh_rsa;
extern const struct ssh_signkey ssh_ecdsa_ed25519;
extern const struct ssh_signkey ssh_ecdsa_nistp256;
extern const struct ssh_signkey ssh_ecdsa_nistp384;
extern const struct ssh_signkey ssh_ecdsa_nistp521;
@ -721,6 +730,8 @@ int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
void *pfnparam);
int ec_generate(struct ec_key *key, int bits, progfn_t pfn,
void *pfnparam);
int ec_edgenerate(struct ec_key *key, int bits, progfn_t pfn,
void *pfnparam);
Bignum primegen(int bits, int modulus, int residue, Bignum factor,
int phase, progfn_t pfn, void *pfnparam, unsigned firstbits);
void invent_firstbits(unsigned *one, unsigned *two);

1189
sshecc.c

File diff suppressed because it is too large Load Diff

View File

@ -39,3 +39,41 @@ int ec_generate(struct ec_key *key, int bits, progfn_t pfn,
return 1;
}
int ec_edgenerate(struct ec_key *key, int bits, progfn_t pfn,
void *pfnparam)
{
struct ec_point *publicKey;
if (bits == 256) {
key->publicKey.curve = ec_ed25519();
} else {
return 0;
}
{
/* EdDSA secret keys are just 32 bytes of hash preimage; the
* 64-byte SHA-512 hash of that key will be used when signing,
* but the form of the key stored on disk is the preimage
* only. */
Bignum privMax = bn_power_2(bits);
if (!privMax) return 0;
key->privateKey = bignum_random_in_range(Zero, privMax);
freebn(privMax);
if (!key->privateKey) return 0;
}
publicKey = ec_public(key->privateKey, key->publicKey.curve);
if (!publicKey) {
freebn(key->privateKey);
key->privateKey = NULL;
return 0;
}
key->publicKey.x = publicKey->x;
key->publicKey.y = publicKey->y;
key->publicKey.z = NULL;
sfree(publicKey);
return 1;
}

View File

@ -569,6 +569,8 @@ const struct ssh_signkey *find_pubkey_alg_len(int namelen, const char *name)
return &ssh_ecdsa_nistp384;
else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp521"))
return &ssh_ecdsa_nistp521;
else if (match_ssh_id(namelen, name, "ssh-ed25519"))
return &ssh_ecdsa_ed25519;
else
return NULL;
}

View File

@ -315,7 +315,7 @@ static int CALLBACK AboutProc(HWND hwnd, UINT msg,
return 0;
}
typedef enum {RSA, DSA, ECDSA} keytype;
typedef enum {RSA, DSA, ECDSA, ED25519} keytype;
/*
* Thread to generate a key.
@ -344,6 +344,8 @@ static DWORD WINAPI generate_rsa_key_thread(void *param)
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);
@ -530,7 +532,7 @@ enum {
IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
IDC_BOX_PARAMS,
IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
IDC_KEYSSH2ECDSA,
IDC_KEYSSH2ECDSA, IDC_KEYSSH2ED25519,
IDC_BITSSTATIC, IDC_BITS,
IDC_ABOUT,
IDC_GIVEHELP,
@ -570,6 +572,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_BITS), 1);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
@ -580,6 +583,8 @@ 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,
MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_PEM,
MF_GRAYED|MF_BYCOMMAND);
@ -600,6 +605,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_BITS), 0);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
@ -610,6 +616,8 @@ 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,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_PEM,
MF_GRAYED|MF_BYCOMMAND);
@ -630,6 +638,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_BITS), 1);
EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND);
@ -640,6 +649,8 @@ 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,
MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
/*
* Enable export menu items if and only if the key type
@ -884,6 +895,7 @@ static int 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(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Key");
state->keymenu = menu1;
@ -965,7 +977,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
"SSH-&1 (RSA)", IDC_KEYSSH1,
"SSH-2 &RSA", IDC_KEYSSH2RSA,
"SSH-2 &DSA", IDC_KEYSSH2DSA,
"SSH-2 &ECDSA", IDC_KEYSSH2ECDSA, NULL);
"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);
@ -1044,6 +1057,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
case IDC_KEYSSH2RSA:
case IDC_KEYSSH2DSA:
case IDC_KEYSSH2ECDSA:
case IDC_KEYSSH2ED25519:
{
state = (struct MainDlgState *)
GetWindowLongPtr(hwnd, GWLP_USERDATA);
@ -1113,6 +1127,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
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,
@ -1140,6 +1156,18 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
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;
@ -1347,6 +1375,9 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
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;
@ -1369,6 +1400,8 @@ static int 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
strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", &tm);
}
@ -1460,6 +1493,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
case IDC_KEYSSH2RSA:
case IDC_KEYSSH2DSA:
case IDC_KEYSSH2ECDSA:
case IDC_KEYSSH2ED25519:
topic = WINHELP_CTX_puttygen_keytype; break;
case IDC_BITSSTATIC:
case IDC_BITS: