1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-06 22:12:47 -05:00

Introduce PPK file format version 3.

This removes both uses of SHA-1 in the file format: it was used as the
MAC protecting the key file against tamperproofing, and also used in
the key derivation step that converted the user's passphrase to cipher
and MAC keys.

The MAC is simply upgraded from HMAC-SHA-1 to HMAC-SHA-256; it is
otherwise unchanged in how it's applied (in particular, to what data).

The key derivation is totally reworked, to be based on Argon2, which
I've just added to the code base. This should make stolen encrypted
key files more resistant to brute-force attack.

Argon2 has assorted configurable parameters for memory and CPU usage;
the new key format includes all those parameters. So there's no reason
we can't have them under user control, if a user wants to be
particularly vigorous or particularly lightweight with their own key
files. They could even switch to one of the other flavours of Argon2,
if they thought side channels were an especially large or small risk
in their particular environment. In this commit I haven't added any UI
for controlling that kind of thing, but the PPK loading function is
all set up to cope, so that can all be added in a future commit
without having to change the file format.

While I'm at it, I've also switched the CBC encryption to using a
random IV (or rather, one derived from the passphrase along with the
cipher and MAC keys). That's more like normal SSH-2 practice.
This commit is contained in:
Simon Tatham
2021-02-20 10:17:45 +00:00
parent 0faeb82ccd
commit 08d17140a0
10 changed files with 444 additions and 60 deletions

View File

@ -49,6 +49,10 @@ static NORETURN PRINTF_LIKE(1, 2) void fatal_error(const char *p, ...)
void out_of_memory(void) { fatal_error("out of memory"); }
/* For platforms where getticks is defined within this code base */
unsigned long (getticks)(void)
{ unreachable("this is a stub needed to link, and should never be called"); }
FILE *f_open(const struct Filename *fn, char const *mode, bool private)
{ unreachable("f_open should never be called by this test program"); }
@ -1141,12 +1145,24 @@ int rsa1_load_s_wrapper(BinarySource *src, RSAKey *rsa, char **comment,
#define rsa1_load_s rsa1_load_s_wrapper
strbuf *ppk_save_sb_wrapper(ssh_key *key, const char *comment,
const char *passphrase)
const char *passphrase, Argon2Flavour flavour,
uint32_t mem, uint32_t passes, uint32_t parallel)
{
/*
* For repeatable testing purposes, we never want a timing-dependent
* choice of password hashing parameters, so this is easy.
*/
ppk_save_parameters save_params;
save_params.argon2_flavour = flavour;
save_params.argon2_mem = mem;
save_params.argon2_passes_auto = false;
save_params.argon2_passes = passes;
save_params.argon2_parallelism = parallel;
ssh2_userkey uk;
uk.key = key;
uk.comment = dupstr(comment);
strbuf *toret = ppk_save_sb(&uk, passphrase);
strbuf *toret = ppk_save_sb(&uk, passphrase, &save_params);
sfree(uk.comment);
return toret;
}