Protecting SSH keys
Public/private Keys are a great way to handle authentication when working with SSH, however public-key cryptography relies on you keeping your private key private. There are a few ways you can achieve this when working with OpenSSH.
Private key files should never be world readable, the parent directory should also be restricted to prevent anyone other than the owner accessing the files in the directory:
$ ls -ld ~/.ssh/ ~/.ssh/id_rsa drwx------. 2 bob bob 38 Jun 6 22:27 /home/bob/.ssh/ -rw-------. 1 bob bob 1679 Jun 6 22:27 /home/bob/.ssh/id_rsa
If for any reason your private key has read access for group or other, you will probably get a message similar to the following when trying to use the key:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Permissions 0664 for '/home/bob/.ssh/id_rsa' are too open.
File permissions can be restricted with chmod:
$ chmod -v 0700 ~/.ssh/ ; chmod -v 0600 ~/.ssh/id_rsa mode of '/home/bob/.ssh/' retained as 0700 (rwx------) mode of '/home/bob/.ssh/id_rsa' changed from 0664 (rw-rw-r--) to 0600 (rw-------)
Note: As well as thinking about file permissions on the key, you should also consider file permissions on disk backups.
Adding a passphrase
Setting restrictive file permissions is a good start, however if someone does manage to get read access to your key, they will be able to use it unless it's encrypted with a passphrase.
Setting a passphrase
When you create a new public/private key pair with ssh-keygen you will normally be prompted for a passphrase:
$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/bob/.ssh/id_rsa): Enter passphrase (empty for no passphrase):
Alternatively, if you already have a private key you can encrypt the key with a
passphrase using the
$ ssh-keygen -p -f ~/.ssh/id_rsa Key has comment '/home/bob/.ssh/id_rsa' Enter new passphrase (empty for no passphrase):
When doing this it's important to think about the complexity of the passphrase. If you use a simple passphrase, an attacker could easily guess the passphrase and unlock the key, assuming they have read access to the key in the first place. The ssh-keygen man page has the following advice on picking a passphrase:
Good passphrases are 10-30 characters long, are not simple sentences or otherwise easily guessable (English prose has only 1-2 bits of entropy per character, and provides very bad passphrases), and contain a mix of upper and lowercase letters, numbers, and non-alphanumeric characters.
As well as picking a good passphrase, it's also important to consider which key format you want to use.
Cracking passphrases and private key formats
Tools such as John the Ripper can be used to try to brute force a
passphrase. This involves two steps, the first step is to extract the hash
$ ./ssh2john.py /home/bob/.ssh/id_rsa > id_rsa.hash
Once the hash has been extracted,
john can be used to try to brute force the
$ ./john id_rsa.hash Using default input encoding: UTF-8 Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
After loading the hash
john will start to guess the passphrase. At
the time of writing the default encryption algorithum for SSH keys is
MD5/3DES. With a single CPU core
john is able to make just under one
million guesses per second:
0g 0:00:00:20 3/3 0g/s 899538p/s 899538c/s 899538C/s berete1
If you want to make an attacker's life difficult you should consider using the
new private key format which was introduced in OpenSSH
6.4. This key format uses a bcrypt
KDF to protect the key which is significantly slower to brute force. Using
john on the same CPU I was only able to make just over 7 guesses per second:
0g 0:00:00:07 1/3 0g/s 7.627p/s 7.627c/s 7.627C/s rsaid
You can switch your key to the new format with the following command:
ssh-keygen -o -p -f ~/.ssh/id_rsa
-a option can also be used to specify how many rounds should be
The last thing to consider is rotating your keys. This effectively boils down to the following steps:
- Generate a new private key.
- Copy the corresponding public key to each remote location you want to authenticate with.
- Check you can access each location using your new private key.
- Remove your old public key from all remote locations.
- Finally remove your private key.
How easy or difficult this will be depends on how many different places you've setup your public key. A very simple example might look something like the following:
# Generate a new private key ssh-keygen -f ~/.ssh/id_rsa_new # Copy your new public key to the remote hosts ssh-copy-id -i ~/.ssh/id_rsa_new remote-box # Verify you can use the new key to login ssh -i ~/.ssh/id_rsa_new remote-box hostname # Remove the old public key ssh -i ~/.ssh/id_rsa_new remote-box 'sed -i "/O1qPS18Ni8F8GqZ0yEjzp665tTPR9F/d" ~/.ssh/authorized_keys' # Delete and replace the old key rm ~/.ssh/id_rsa ~/.ssh/id_rsa.pub mv ~/.ssh/id_rsa_new ~/.ssh/id_rsa mv ~/.ssh/id_rsa_new.pub ~/.ssh/id_rsa.pub