Bonus Rounds: increasing password security for ssh and other keys

Securely hashed passwords using a long, random SALT and a modern hashing algorithm are state of the art today. Except for the bit length of SALT and hash, not much has changed since the 90s though. Computing power available for hash cracking on the other hand grew multiple magnitudes in the same time.

Meanwhile nothing has changed in human capabilities to remember passwords. The Web 2.0 poweruser of 2013 can't store better passwords in his brain than his mosaic-surfing alter ego 20 years ago. So technically, password security has massively decreased since. The salt mainly hinders massive cracking of multiple hashes and even 128 bit are already much more than most passwords ever will have in entropy.

The soluting: adding complexity to the hash calculation. The most common way is more or less simply hashing multiple times, called "rounds" or "iterations". Instead of once, the hash function is applied for example 2000 times, effectively slowing down an attacker by about the same factor. Passwords which could be cracked in a week before now would withstand approximately 40 years - quite an improvement.

For current Linux passwords this is easily enabled. In /etc/login.defs for example a 256 Bit SHA hash using 10.000 rounds can be selected, taking effect for all newly set passwords since the change:

ENCRYPT_METHOD SHA256
SHA_CRYPT_MIN_ROUNDS 10000

The default for SHA256 and SHA512 by default already is 5000 rounds. Using those hashes generally is a good idea everywhere, where password have to be stored, so as well for mail accounts or logins of web applications.

Prominent Hacks

You might think now: nobody should have access to the password hashes in a database or the shadow file anyway. That's of course true! But in the past there have been many prominent system compromises, in which hashes of thousands of accounts were stolen and sometimes even published. Of course that's a sysadmin's worst nightmare already and not good for a company's reputation. But if you have to admit afterwards, that your hashes were not stored in a state of the art manner, it might as well have big legal implications, like for example the sueing of LinkedIn after a hack has showed last year (see: LinkedIn hit with 5 Million class action suit)

A similar problem arises for hard disk encryption - except that there a potential attacker always alrady has access to the data. Luckily, LUKS users on Linux easily can use the parameter --iter-time x on a cryptsetup luksAddKey-command to specify the amount of time (in milliseconds), which should be used for iterating.

Already a few seconds (which will be a delay each time the encrypted volume as to be unlocked) result in millions of iterations and therefore increase security of the password massively. As long as your data is not compromised yet it also is easy to add a new, better secured passphrase to a LUKS container, and then remove the old one.

If you are so convinced of iterations now, that you want to use them everywhere, you will soon get to a problem which was the initial motivation for this article: ssh private keys. They are among the most valuable private keys a sysadmin might have - allowing access to sometimes a dozen or more servers, sometimes up to root access. But: ssh-keygen has no option for rounds!

And if you look closer: that's because there aren't any! Ssh private keys use no iterations, therefore a passphrase today has to be a really good one to withstand a targeted attack for a longer time.

That's unacceptable!

My research soon showed me: there's hope. ssh-keygen can't help, but OpenSSH is able to read keys generated with OpenSSL in the PKCS8 format. 2048 iterations using the well established PBKDF2 algorithm are used there, already a massive gain. Securing your existing key is easy:

$ mv id_rsa id_rsa.old
$ openssl pkcs8 -topk8 -v2 des3 -in id_rsa.old -out id_rsa

Note

After successfully testing the new key, you can use shred -u id_rsa.old to securely delete the old one.

You will have to enter your passphrase and of course a new one (can be the same). OpenSSH will accept that new key like an own one, just ssh-keygen can't create them directly.

Better is not good enough...

2048 iterations is notthing given today's workstations and servers computing powers. But openssl offers no option to increase that. So there's only one option: Open Source! So I opened the sourcecode. It was easy to identify the spot, where the default could be changed, iter = PKCS12_DEFAULT_ITER; in apps/pkcs8.c - which is defined as 2048 and one could simply enter another value there and rebuild openssl.

A little bit more comfort gives the adding of a new commandline option. I built a short patch which should apply to most of the currently used openssl versions. With the patch you can add -iters 100000 to the commandline shown before to get 100.000 iterations.

--- openssl-1.0.0/apps/pkcs8.c  2010-01-22 21:17:29.000000000 +0100
+++ openssl-1.0.0/apps/pkcs8.c.iter     2013-03-27 00:42:09.808969739 +0100
@@ -157,6 +157,21 @@ int MAIN(int argc, char **argv)
                        topk8 = 1;
                else if (!strcmp (*args, "-noiter"))
                        iter = 1;
+               else if (!strcmp (*args, "-iters")) {
+                        if (args[1])
+                                {
+                                args++;
+                                iter = atol(*args);
+                                if (iter < 0)
+                                        {
+                                        BIO_printf(bio_err,
+                                                "Illegal iter count %s\n",
+                                                *args);
+                                        badarg = 1;
+                                        }
+                                }
+                        else badarg = 1;
+                        }
                else if (!strcmp (*args, "-nocrypt"))
                        nocrypt = 1;
                else if (!strcmp (*args, "-nooct"))

The good news: you only need the patched OpenSSL to create the keys, not on every system where they should be used. And for openssh the developers are currently planning a new key format, so in the future ssh-keygen might be able to create better secured keys directly, probably even using a more advanced key derivation algorithm like scrypt.

For OpenSSL I hope it will be possible to integrate my patch or at least a similar function into the official sourcecode. Not mainly for ssh keys, but all the other OpenSSL keys like those of OpenVPN, Mail, Web and IMAP Servers.

Note

It's not always desired to add passphrases to such keys. But whenever somone goes through the hassle of securing his SSL keys with a passphrase, many iterations are probably especially usefull.

One question remains: how many rounds to use? In environments where hashes are used frequently and only a last line of defense anyway, like mail server logins, it should not be overdone. It adds load to the server and after a compromise the change of all passwords might be recommended anyway. On servers with only a few logins per hour or even less, a much higher value than the default might be feasable.

Data that has to be unlocked at most a few times a day - and where the password is usually entered manually - is quite a different topic. For an ssh key, your hard disk encryption or the private key of a VPN connection, iterating a second or more will not really interrupt your workflow noticeable, entering the passphrase will take most of the time. For a seldom used mobile USB disk or a server, which is only restarted every few weeks, even a minute or so might be a wise choice... Especially in the last case I am happy to now be able to add as many rounds as I want. One of the advantages of open sources!


Comments

  1. mupp

    mupp (1 year, 8 months) # Reply

    ssh-keygen -a

Comments are closed.