Creating a new SSH key with ed25519 encryption

A while ago, I prepared notes about creating an SSH key for use with Gitlab (and other SSH-based servers). That guide, https://pj.freefaculty.org/guides/crmda_guides/34.gitlab/34.gitlab.pdf explains the basic ideas of SSH keys.

Today I learned that when interacting with an SSH server, the USER can control, to a significant extent, the type of security that is used. This is because the USER creates the SSH key used for key-based authentication and keys can be encrypted in several different formats.

My "old" key (from last year) was created with the RSA encryption. RSA was an upgrade over DSA. So when I log into a remote system that supports several protocols, the system notices my key is RSA.

You can see that for yourself in the shell if you run ssh -v your_server_name_here. In the output, you'll see what encryption your session is using and there will also be info about what's possible. I see

$ ssh -v kauffy
debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521>

debug1: kex: host key algorithm: ecdsa-sha2-nistp256
...
debug1: Will attempt key: /home/pauljohn/.ssh/PJ_kauffeykey_20190624 RSA SHA256:684fc0VEO/glopItyGook explicit agent

The server supports both ed25519 and ecdsa. The former is preferred. And when people want to create keys that will interact with my systems, I will ask them also to create ed25519 keys.

First, I make sure my system's ssh-keygen function is able to do this. Check the help page:

$ ssh-keygen --help
SYNOPSIS
 ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa] [-N new_passphrase]
                [-C comment] [-f output_keyfile]

This version of ssh-keygen can work with dsa, ecdsa, ed22519 and rsa. In the old days we had dsa. Now, dsa is discouraged/insecure and should be removed from the list. Default keys use rsa. Now rsa is considered adequate, but not as good as the others. Now we want ed25519, or, if the server does not support that, I would need ecdsa. So I might as well create a new key for each one.

I always specify the key file name, so I can tell which key goes with which website. Today I did this ( I cd into the ~/.ssh folder so the key file will end up where I want it to be.).

$ cd .ssh
$ ssh-keygen -a 100 -t ed25519 -f "PJ-ed25519-20200415" -C "PJ-ed25519-20200415"
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/pauljohn/.ssh/PJ-ed25519-20200415.
Your public key has been saved in /home/pauljohn/.ssh/PJ-ed25519-20200415.pub.
The key fingerprint is:
SHA256:dzhTwEx1KDcx87hNFqKdP8ZX4JlpsnneVGalQc1sSXM PJ-ed25519-20200415
The key's randomart image is:
+--[ED25519 256]--+
|         +o.*+B*E|
|          +++X XO|
|          .o*.@.=|
|           o % oo|
|        S = = B o|
|         . + + = |
|              . .|
|                 |
|                 |
+----[SHA256]-----+

The -C flag gives a comment that is saved at the end of the public key. Many people put their email there. I would rather put a reminder to myself of which key this is. I specify a file name with -f. Again, many people ignore the name, but it is important to me to know which key is which, and I put a format and a date. The -a parameter asks for the algorithm to apply a lot of iterated distortions to the security system to discourage brute-force password cracking efforts.

I have one project where the server does not yet allow ed25519 keys, so I also need an ecdsa key. For this one, I specify the bits parameter at the maximum value:

$ cd ~/.ssh
$ ssh-keygen -b 521  -t ecdsa -C "pauljohn_ecdsa_20200415" -f "PJ-ecdsa-20200415"
Generating public/private ecdsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in PJ-ecdsa-20200415.
Your public key has been saved in PJ-ecdsa-20200415.pub.
The key fingerprint is:
SHA256:ZakN2sprQk6hUwk5IGVTKQI2pP10OKMReY03QYgHn9E pauljohn_ecdsa_20200415
The key's randomart image is:
+---[ECDSA 521]---+
|****oBo.         |
|=oO+*+E    .     |
|..o*Bo... +      |
|   =++ o *       |
|  .o... S .      |
|  o o. .         |
|   =  o          |
|    o ..         |
|     o.          |
+----[SHA256]-----+

After that, I've got 2 new keys, each with public and private parts:

$ ls -la
[snip]

-rw-------   1 pauljohn pauljohn   801 Apr 15 14:17 PJ-ecdsa-20200415
-rw-r--r--   1 pauljohn pauljohn   277 Apr 15 14:17 PJ-ecdsa-20200415.pub
-rw-------   1 pauljohn pauljohn   464 Apr 15 14:16 PJ-ed25519-20200415
-rw-r--r--   1 pauljohn pauljohn   101 Apr 15 14:16 PJ-ed25519-20200415.pub

There is a problem that you will run into if you have several different SSH keys. If you try to log in on a server, it will look through your keys and try one at a time. The server is configured to check a few of your keys and then give up. The way to solve that is to tell the server which authorization key should be used when you log in on the website.

There are two ways to do this. First, on the command line, add a parameter to tell ssh which key to use. For example, ssh -i ~/.ssh/PJ-ed25519-20200415 would work. If the path to the key has any spaces or special characters (unwise!), you'd need quotes on the key's name. But don't be a silly person and create a key with spaces or symbols like * or &. That's just wrong.

Second, the method I actually use is to create a stanza in my SSH configuration, a file called ~/.ssh/config. These configurations are just cut-and-paste things, nothing fancy. Here's the top of the file

Host subversions.gnu.org
     Protocol 2

Host kauffy
     HostName 42.73.187.92
     User pauljohn
     IdentityFile ~/.ssh/PJ-ed25519-20200415
     KeepAlive yes
     ServerAliveInterval 10
     IdentitiesOnly yes

On the server, I need to insert the content of my file ~/.ssh/PJ-ed25519-20200415.pub into the file called ~/.ssh/authorized_keys. This can be done in various ways. Because I'm old, I use scp to transfer the key to the server, then simply add the key to the file with cat. On the server, run:

$ cd .ssh
$ cat ~/PJ-ed25519-20200415.pub >> authorized_keys

Other people use wrapper scripts that can transfer the key pub file to the server an append it to authorized_keys. Perhaps your OS has a shortcut like that. But I don't see any reason to rely on somebody else's scripting magic when this is a perfectly understandable and doable thing for an average user. There's no magic in it.

After this, whenever I want to ssh connect with the server, I run in the terminal

$ ssh kauffy

After all this, I better make sure it actually uses ecdsa encryption. So I go to my client computer and run

$ ssh -v kauffy

and in the output, I find comments indicating that it did work:

debug1: identity file /home/pauljohn/.ssh/PJ-ed25519-20200415 type 3
debug1: identity file /home/pauljohn/.ssh/PJ-ed25519-20200415-cert type -1
...
debug1: Offering public key: /home/pauljohn/.ssh/PJ-ed25519-20200415 ED25519 SHA256:gobbeldyGook explicit agent
debug1: Server accepts key: /home/pauljohn/.ssh/PJ-ed25519-20200415 ED25519 SHA256:gobbeldyGook explicit agent
debug1: Authentication succeeded (publickey).

Special thanks to Wes Mason at KU's ITTC for suggestion to try ed25519 and, failing that, ecdsa.

About pauljohn

Paul E. Johnson is a Professor of Political Science at the University of Kansas. He is an avid Linux User, an adequate system administrator and C programmer, and humility is one of his greatest strengths.
This entry was posted in Linux. Bookmark the permalink.

Leave a Reply