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

Windows PuTTYgen: support cmdgen's key-type and PPK options.

This imports the following options from command-line PuTTYgen, which
all correspond to controls in Windows PuTTYgen's GUI, and let you set
the GUI controls to initial values of your choice:

  -t <key type>
  -b <bits>
  -E <fingerprint type>
  --primes <prime gen policy>
  --strong-rsa
  --ppk-param <KDF parameters or PPK version etc>

The idea is that if someone generates a lot of keys and has standard
non-default preferences, they can make a shortcut that passes those
preferences on the command line.
This commit is contained in:
Simon Tatham 2022-01-15 18:30:34 +00:00
parent dc183e1649
commit 11aa9ab8f3
2 changed files with 242 additions and 9 deletions

View File

@ -478,6 +478,82 @@ you have generated an SSH-1 private key using OpenSSH or
Hence, the export options are not available if you have generated an
SSH-1 key.
\S{puttygen-cli} PuTTYgen command-line configuration
PuTTYgen supports a set of command-line options to configure many of
the same settings you can select in the GUI. This allows you to start
it up with your own preferences ready-selected, which might be useful
if you generate a lot of keys. (For example, you could make a Windows
shortcut that runs PuTTYgen with some command line options, or a batch
file or Powershell script that you could distribute to a whole
organisation containing your local standards.)
The options supported on the command line are:
\dt \cw{\-t} \e{keytype}
\dd Type of key to generate. You can select \c{rsa}, \c{dsa},
\c{ecdsa}, \c{eddsa} or \c{rsa1}. See \k{puttygen-keytype}.
\dt \cw{\-b} \e{bits}
\dd Size of the key to generate, in bits. See \k{puttygen-strength}.
\dt \cw{\-\-primes} \e{method}
\dd Method for generating prime numbers. You can select \c{probable},
\c{proven}, and \c{proven-even}. See \k{puttygen-primes}.
\dt \cw{\-\-strong-rsa}
\dd When generating an RSA key, make sure the prime factors of the key
modulus are \q{strong primes}. A strong prime is a prime number chosen
to have a particular structure that makes certain factoring algorithms
more difficult to apply, so some security standards recommend their
use. However, the most modern factoring algorithms are unaffected, so
this option is probably not worth turning on \e{unless} you have a
local standard that recommends it.
\dt \cw{\-\-ppk-param} \e{key}\cw{=}\e{value}\cw{,}...
\dd Allows setting all the same details of the PPK save file format
described in \k{puttygen-save-params}.
\lcont{
Aspects to change are specified as a series of \e{key}\cw{=}\e{value} pairs
separated by commas. The \e{key}s are:
\dt \cw{version}
\dd The PPK format version: either \cw{3} or \cw{2}.
\dt \cw{kdf}
\dd The variant of Argon2 to use: \cw{argon2id}, \cw{argon2i}, and
\cw{argon2d}.
\dt \cw{memory}
\dd The amount of memory needed to decrypt the key, in Kbyte.
\dt \cw{time}
\dd Specifies how much time is required to attempt decrypting the key,
in milliseconds.
\dt \cw{passes}
\dd Alternative to \cw{time}: specifies the number of hash passes
required to attempt decrypting the key.
\dt \cw{parallelism}
\dd Number of parallelisable threads that can be used to decrypt the
key.
}
\H{pubkey-gettingready} Getting ready for public key authentication
Connect to your SSH server using PuTTY with the SSH protocol. When the

View File

@ -629,6 +629,15 @@ static DWORD WINAPI generate_key_thread(void *param)
return 0;
}
struct InitialParams {
int keybutton;
int primepolicybutton;
bool rsa_strong;
FingerprintType fptype;
int keybits;
int eccurve_index, edcurve_index;
};
struct MainDlgState {
bool generation_thread_exists;
bool key_exists;
@ -1393,15 +1402,16 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
cp.ypos = ymax;
endbox(&cp);
}
ui_set_key_type(hwnd, state, IDC_KEYSSH2RSA);
ui_set_primepolicy(hwnd, state, IDC_PRIMEGEN_PROB);
ui_set_rsa_strong(hwnd, state, false);
ui_set_fptype(hwnd, state, fptype_to_idc(SSH_FPTYPE_DEFAULT));
SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEY_BITS, false);
struct InitialParams *params = (struct InitialParams *)lParam;
ui_set_key_type(hwnd, state, params->keybutton);
ui_set_primepolicy(hwnd, state, params->primepolicybutton);
ui_set_rsa_strong(hwnd, state, params->rsa_strong);
ui_set_fptype(hwnd, state, fptype_to_idc(params->fptype));
SetDlgItemInt(hwnd, IDC_BITS, params->keybits, false);
SendDlgItemMessage(hwnd, IDC_ECCURVE, CB_SETCURSEL,
DEFAULT_ECCURVE_INDEX, 0);
params->eccurve_index, 0);
SendDlgItemMessage(hwnd, IDC_EDCURVE, CB_SETCURSEL,
DEFAULT_EDCURVE_INDEX, 0);
params->edcurve_index, 0);
/*
* Initially, hide the progress bar and the key display,
@ -2013,6 +2023,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
int argc;
char **argv;
int ret;
struct InitialParams params[1];
dll_hijacking_protection();
@ -2024,6 +2035,16 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
*/
init_help();
params->keybutton = IDC_KEYSSH2RSA;
params->primepolicybutton = IDC_PRIMEGEN_PROB;
params->rsa_strong = false;
params->fptype = SSH_FPTYPE_DEFAULT;
params->keybits = DEFAULT_KEY_BITS;
params->eccurve_index = DEFAULT_ECCURVE_INDEX;
params->edcurve_index = DEFAULT_EDCURVE_INDEX;
save_params = ppk_save_default_parameters;
split_into_argv(cmdline, &argc, &argv, NULL);
int argbits = -1;
@ -2052,15 +2073,151 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
} else if (match_opt("-restrict-acl", "-restrict_acl",
"-restrictacl")) {
restrict_process_acl();
} else if (match_optval("-t")) {
if (!strcmp(val, "rsa") || !strcmp(val, "rsa2")) {
params->keybutton = IDC_KEYSSH2RSA;
} else if (!strcmp(val, "rsa1")) {
params->keybutton = IDC_KEYSSH1;
} else if (!strcmp(val, "dsa") || !strcmp(val, "dss")) {
params->keybutton = IDC_KEYSSH2DSA;
} else if (!strcmp(val, "ecdsa")) {
params->keybutton = IDC_KEYSSH2ECDSA;
} else if (!strcmp(val, "eddsa")) {
params->keybutton = IDC_KEYSSH2EDDSA;
} else if (!strcmp(val, "ed25519")) {
params->keybutton = IDC_KEYSSH2EDDSA;
argbits = 255;
} else if (!strcmp(val, "ed448")) {
params->keybutton = IDC_KEYSSH2EDDSA;
argbits = 448;
} else {
opt_error("unknown key type '%s'\n", val);
}
} else if (match_optval("-b")) {
argbits = atoi(val);
} else if (match_optval("-E")) {
if (!strcmp(val, "md5"))
params->fptype = SSH_FPTYPE_MD5;
else if (!strcmp(val, "sha256"))
params->fptype = SSH_FPTYPE_SHA256;
else
opt_error("unknown fingerprint type '%s'\n", val);
} else if (match_optval("-primes")) {
if (!strcmp(val, "probable") ||
!strcmp(val, "probabilistic")) {
params->primepolicybutton = IDC_PRIMEGEN_PROB;
} else if (!strcmp(val, "provable") ||
!strcmp(val, "proven") ||
!strcmp(val, "simple") ||
!strcmp(val, "maurer-simple")) {
params->primepolicybutton = IDC_PRIMEGEN_MAURER_SIMPLE;
} else if (!strcmp(val, "provable-even") ||
!strcmp(val, "proven-even") ||
!strcmp(val, "even") ||
!strcmp(val, "complex") ||
!strcmp(val, "maurer-complex")) {
params->primepolicybutton = IDC_PRIMEGEN_MAURER_COMPLEX;
} else {
opt_error("unrecognised prime-generation mode '%s'\n", val);
}
} else if (match_opt("-strong-rsa")) {
params->rsa_strong = true;
} else if (match_optval("-ppk-param", "-ppk-params")) {
char *nextval;
for (; val; val = nextval) {
nextval = strchr(val, ',');
if (nextval)
*nextval++ = '\0';
char *optvalue = strchr(val, '=');
if (!optvalue)
opt_error("PPK parameter '%s' expected a value\n", val);
*optvalue++ = '\0';
/* Non-numeric options */
if (!strcmp(val, "kdf")) {
if (!strcmp(optvalue, "Argon2id") ||
!strcmp(optvalue, "argon2id")) {
save_params.argon2_flavour = Argon2id;
} else if (!strcmp(optvalue, "Argon2i") ||
!strcmp(optvalue, "argon2i")) {
save_params.argon2_flavour = Argon2i;
} else if (!strcmp(optvalue, "Argon2d") ||
!strcmp(optvalue, "argon2d")) {
save_params.argon2_flavour = Argon2d;
} else {
opt_error("unrecognised kdf '%s'\n", optvalue);
}
continue;
}
char *end;
unsigned long n = strtoul(optvalue, &end, 0);
if (!*optvalue || *end)
opt_error("value '%s' for PPK parameter '%s': expected a "
"number\n", optvalue, val);
if (!strcmp(val, "version")) {
save_params.fmt_version = n;
} else if (!strcmp(val, "memory") ||
!strcmp(val, "mem")) {
save_params.argon2_mem = n;
} else if (!strcmp(val, "time")) {
save_params.argon2_passes_auto = true;
save_params.argon2_milliseconds = n;
} else if (!strcmp(val, "passes")) {
save_params.argon2_passes_auto = false;
save_params.argon2_passes = n;
} else if (!strcmp(val, "parallelism") ||
!strcmp(val, "parallel")) {
save_params.argon2_parallelism = n;
} else {
opt_error("unrecognised PPK parameter '%s'\n", val);
}
}
} else {
opt_error("unrecognised option '%s'\n", amo.argv[amo.index]);
}
}
save_params = ppk_save_default_parameters;
/* Translate argbits into eccurve_index and edcurve_index */
if (argbits > 0) {
switch (params->keybutton) {
case IDC_KEYSSH2RSA:
case IDC_KEYSSH1:
case IDC_KEYSSH2DSA:
params->keybits = argbits;
break;
case IDC_KEYSSH2ECDSA: {
bool found = false;
for (int j = 0; j < n_ec_nist_curve_lengths; j++)
if (argbits == ec_nist_curve_lengths[j]) {
params->eccurve_index = j;
found = true;
break;
}
if (!found)
opt_error("unsupported ECDSA bit length %d", argbits);
break;
}
case IDC_KEYSSH2EDDSA: {
bool found = false;
for (int j = 0; j < n_ec_ed_curve_lengths; j++)
if (argbits == ec_ed_curve_lengths[j]) {
params->edcurve_index = j;
found = true;
break;
}
if (!found)
opt_error("unsupported EDDSA bit length %d", argbits);
break;
}
}
}
random_setup_special();
ret = DialogBox(hinst, MAKEINTRESOURCE(201), NULL, MainDlgProc) != IDOK;
ret = DialogBoxParam(hinst, MAKEINTRESOURCE(201), NULL, MainDlgProc,
(LPARAM)params) != IDOK;
cleanup_exit(ret);
return ret; /* just in case optimiser complains */