OpenSSH Primer

OpenSSH Setup and Administration

This is intended as a guide to basic OpenSSH administration for both the client and the server.

This guide is a split-off from the Git Setup page, as SSH administration is much broader in scope than just running a Git server.

This guide assumes some familiarity with how to use a UNIX shell account, using SSH to connect to a server, and using a text editor from a command line interface to modify a text file.

  1. UNIX Shell Basics
  2. SSH Basics
  3. VIM Basics

Brief History: From R-Tools to OpenSSH

Prior to my own introduction to the UNIX world in 1998, a standard set up tools for the remote administration of UNIX systems existed called the R-tools:

  1. rlogin
  2. rsh
  3. rcp
  4. rwho
  5. rexec

These utilities were developed at the University of California at Berkeley shortly after the TCP/IP networking stack had been invented. None of them are safe to use and are no longer included in modern UNIX derivatives (er, I hope…)

While the set of tools was quite innovative at the time, one thing they completely lacked was security. They allowed remote administration of a UNIX system but they also allowed anyone listening on the network to see everything, including passwords, as they were sent in plain text.

During 1995, a Finnish programmer named Tatu Ylönen developed the first version of the Secure Shell protocol, commonly known as SSH, that provided a means of remote UNIX system administration with the connection over the network using encryption.

SSH adoption rapidly grew, and had become the standard method for remote UNIX system administration by the late 90s. Early versions of SSH were free software, but later versions had license restrictions that prevented Free Software distributions from being allowed to distribute them. Secure system administration was becoming a privilege of those who could afford it, those who could not had to use the older versions of the software.

Björn Grönvall created a fork of the last version of the original SSH that had a free software license, and called it OSSH.

OpenSSH blowfish wearing sunglasses and a tie, carrying a suitcase marked 'Top Secret'In 1999, OpenBSD released a fork of Björn Grönvall’s implementation called OpenSSH that had many improvements, and it quickly became the dominant SSH implementation in Free Software UNIX like operating systems, such as all the various flavors of BSD and Linux.

Commercial UNIX such as Solaris often still included the proprietary SSH implementations, but even on those systems the system administrators very often installed OpenSSH (often along with many of the GNU Utilities) simply because it had become superior to the proprietary implementations.

In 2006, the IETF published several RFCs that defined the second version of the protocol that included many improvements, including Forward Secrecy through Diffie-Hellman Key Exchange.

The second version of the protocol was not compatible with the first version of the protocol. However quite a few clients, including OpenSSH, were able to speak both protocols.

This was important because even though free UNIX implementations were quick to adopt the second version of the protocol, the commercial UNIX implementation (like OS X) that people paid money for were often slow to adopt it.

At this point in time, it is no longer considered safe to use the first version of the protocol.

SSH Server Authentication

With the HTTPS protocol, authentication that the server is who it says it is is performed using PKI (Public Key Infrastructure). The server has a public/private key pair. The public key is distributed in what is called an X.509 Certificate. This certificate is usually signed by a Certificate Authority that the browser implicitly trusts.

When an HTTPS server sends a certificate that is either self-signed or signed by a Certificate Authority that the browser does not trust, or if the certificate is expired, the browser will either refuse the connection or give a very strong warning to the user requiring that the user acknowledge they understand the server may not be who it claims to be.

PKI allows the browser to implicitly trust that the server is who it says it is without requiring user interaction as long as the server uses a certificate signed by a Certificate Authority the browser already trusts.

Trust On First Use

SSH works a bit differently. The server also uses public key cryptography but it does not use PKI to authenticate the server. It uses an authentication mechanism called Trust On First Use (often abbreviated as TOFU).

When you connect to an SSH server, your client looks at the fingerprint. If the client has connected to the same domain before and the fingerprint does not match, a very nasty warning is given:

[user@host ~]$ ssh example.net
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:vJ3EyZCb9kujvwYko3JU3r3X1FLpvAIXMZYee0exr74.
Please contact your system administrator.
Add correct host key in /home/user/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/user/.ssh/known_hosts:29
ECDSA host key for [example.net] has changed and you have requested strict checking.
Host key verification failed.
[user@host ~]$

On the other hand if you do not already have a stored fingerprint for the host, it is a first use scenario and the client will ask you if you want to trust it on it’s first use:

[user@host ~]$ ssh example.net
The authenticity of host '[example.net] ([2606:2800:220:1:248:1893:25c8:1946])' can't be established.
ECDSA key fingerprint is SHA256:vJ3EyZCb9kujvwYko3JU3r3X1FLpvAIXMZYee0exr74.
ECDSA key fingerprint is MD5:e3:51:bf:c1:09:e4:a5:57:33:a1:e1:17:5a:dc:55:db.
Are you sure you want to continue connecting (yes/no)?

This allows the user to visually inspect the fingerprint and verify that is correct (e.g. against a published fingerprint the system administrator has made available elsewhere) and decide whether or not they want to continue connecting.

When the user indicates trust in the fingerprint by answering yes, the fingerprint is stored in user’s ~/.ssh/known_hosts file.

When the user connects and the fingerprint of the public key the server sends has a fingerprint that matches a fingerprint already defined for that host (both hostname and resolved IP address), the client trusts the server and authentication can then begin.

Advantages to TOFU

The biggest advantage to TOFU is the simplicity. There is not a Certificate Authority infrastructure where the user must have the right root certificates installed, there are not certificates to expire, and the client can not be fooled by a fraudulently signed certificate. Also, Iguanas really like it.

Disadvantages to TOFU

The user rarely actually validates the fingerprint is valid the first time they connect to a server, even when the system administrator has published the valid fingerprint.

There is no mechanism by which to revoke a public key. If a server is hacked and the private SSH keys are potentially stolen, even if the system administrator creates fresh keys, the hacker can still use the stolen keys to fool clients that already have the key stored. All users must be notified that the old key has been compromised, what the new fingerprint is, and how to proceed.

When the key does change, updating the saved fingerprint is beyond the skill of many users. Users who are familiar with command line can update, but many Internet applications use SSH to tunnel communication with other machines over the network, the user may not even know enough to know that is happening.

When a user does get the warning that a MITM attack may be taking place, a surprisingly large number of users will often just assume the system administrator changed the keys. Without verifying that is the case, they will blissfully delete the old fingerprint from the ~/.ssh/known_hosts file and then accept the new fingerprint and proceed to connect.

If the user authenticates with a password, this can allow the attacker to steal the user’s password.

Fingerprint Validation with SSHFP

If the authoritative DNS server for the domain the user is connecting to implements DNSSEC, and only if the authoritative DNS server for the domain implements DNSSEC, a new standard called SSHFP allows a system administrator to publish the SSH daemon fingerprint as a DNS record.

Instead of using the ~/.ssh/known_hosts file to verify the fingerprint, clients will be able to use DNS to verify the fingerprint.

This eliminates the issues that exist with TOFU and provides proper validation of the fingerprint every time the client connects.

Unfortunately at this time, most DNS zones do not implement DNSSEC and SSHFP can not be used without DNSSEC. Also at this time, many SSH clients are not capable of implementing SSHFP even when the DNS zone is secured by DNSSEC.

For more information on SSHFP, please see https://blog.webernetz.net/sshfp-authenticate-ssh-fingerprints-via-dnssec/

SSH Client Authentication

There are typically two methods used by a client to authenticate with an account on the server:

  1. Password Authentication
  2. Public Key Authentication

There are also other methods (e.g. Kerberos etc.) but I have not had an opportunity to play with them, and they seem to seldom be the best solution. There are probably cases where they are appropriate but I can not comment on them.

The first method is the most common method, but it is also the most dangerous method because it gives both the potential for a brute force login (where a hacker guesses the password associated with a user account) and for password theft (either by a Man-In-The-Middle attack, or observing the user enter the password on a keyboard).

The second method is more secure but requires some additional set up.

Password Authentication

With this type of authentication, the user simply supplies their user account password when establishing an SSH connection. This is the simplest method and is enabled by default though in many cases it is advisable to turn it off.

Sending passwords over a network as a means of user authentication is one of the most dangerous means of authentication there is. Seriously.

In addition to the threat of passwords being stolen via a Man-In-The-Middle attack, the kind of string that makes a good password is not the kind of string that the human brain is good at remembering. This leads to very bad practices of using weak passwords, re-using passwords, and writing them down.

Public Key Authentication

With Public Key Authentication, the user creates a cryptographic Private / Public key pair. A copy of the Public Key is installed in the user account on the server the user connects to (usually appended to the ~/.ssh/authorized_keys file) and the private key is kept on the machine the SSH client is connecting from.

The private key usually has a password / passphrase that locks it, but this password / passphrase is never transmitted over the network. Rather it is a second line of defense in the event that a hacker has managed to steal the user’s private key.

Once the client has validated the server is who the server claims to be, the client responds to a challenge the server sends and signs the response using the private key.

The server then uses the public key installed within the authorized_keys file to verify that the response was signed by the corresponding private key. If it passes the check, authentication is complete. Otherwise authentication fails, and either the connection is refused or it falls back to password authentication if password authentication has not been disabled.

Client-Side Setup

On the client, generate a private / public key pair for that account. You can re-use the same key pair with many different servers but it is a very bad idea to use the same key pair with more than one client, the private key used by a particular client should always be generated on the client and be unique to that client.

To generate a key pair with OpenSSH, there are three options to the ssh-keygen command that I personally use:

-t rsa
This tells ssh-keygen that I want an RSA key. In CentOS 7 several other options exist: dsa, ecdsa, ed22519, rsa1. RSA1 is for version 1 protocol, which should not be used. DSA is deprecated and should not be used. ECDSA and ed22519 are good choices too but not all servers you may wish to connect to support them.
-b 4096
The default for RSA keys is 2048 bits. While that is probably strong enough, modern hardware easily support 4096 bit RSA keys without causing processing lag, so that is what I use. If you want to use ECDSA instead of RSA, see the ssh-keygen man page. This option is ignored when using ed22519.
-C “username@example.org”
This option only provides a comment. I usually just use my work e-mail address, which is standard practice, but what you put there does not really matter if anything at all.

An example:

[username@yourworkstation ~]# ssh-keygen -t rsa -b 4096 -C "username@example.org"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa):
Created directory '/home/username/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/username/.ssh/id_rsa.
Your public key has been saved in /home/username/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:tgiaS0CCecz+37Np4vvJJHQqxUwSPcD/NgpWf0iePVY someusername@example.org
The key's randomart image is:
+---[RSA 4096]----+
|=o.              |
|o=+              |
|oo*..            |
| B = .           |
|..=.+   S        |
|.ooo * + o   E   |
|.++.o + * + .    |
|o.=... +.= =     |
|...+  =+. o .    |
+----[SHA256]-----+
[username@yourworkstation ~]$

When it asks for the file to save it in, just go with the default ~/.ssh/id_rsa and keep things simple.

While in theory you can have different keypairs for different servers you connect to, personally I think that is a bad idea just because it makes things more complex. Just use the same keypair for all servers you will be connecting to. If a hacker gets one private key they likely got them all anyway, so no extra security is actually provided by using multiple key pairs.

If you insist on using multiple key pairs, you will need to create a ~/.ssh/config file to tell the OpenSSH client which private key to use when connecting to which server. Avoid that.

When it asks for a passphrase, it can be tempting to leave it blank. Don’t. Blank pass phrases should only be used for automated processes, and even that has risks that sometimes make it the wrong choice.

Humans using SSH should always have a pass phrase. I like to use a made-up sentence that I can remember with a nonsense word embedded within it, for example I might use:

Johnny ate 4d#ap8 an apple dinosaur and said it was quite deciduous.

That is a very uncommon nonsense sentence but is easy to remember, with a little randomized bit inserted between the second and third word.

Note that at least in CentOS 7 and I suspect on other desktops, once you have unlocked your private key to connect to a server it stays unlocked for awhile, you do not have to enter the pass phrase every single time you use ssh, it just connects. Sweet.

Note that if you forget your passphrase, there is no way to recover it. Your only option is to generate a new key pair.

Server Side Setup

The above command will generate two files within your ~/.ssh directory:

  1. id_rsa
  2. id_rsa.pub

The first is your private key.

Gandalf - Keep It Secret, Keep It Safe

The second, id_rsa.pub (node the .pub extension), is your public key. That is what needs to be installed on the server.

If the system administrator of the server you are connecting has disabled ssh login with password authentication, you will have to have your system administrator install the public key for you.

To install your public key yourself, you need to copy the file to your server account:

[username@yourworkstation ~]$ cd ~/.ssh
[username@yourworkstation .ssh]$ scp id_rsa.pub awonder@whatever.example.org:
awonder@whatwver.example.org's password:
id_rsa.pub                                         100%  742  18.9KB/s 00:00

Then log in to your account there:

[username@yourworkstation ~]$ ssh -l awonder whatever.example.org
awonder@whatever.example.org's password: 
Last login: Thu Jun  7 23:09:58 2018 from 2600:1010:b00f:90e4:3087:d890:629a:ea3d
[awonder@whatever ~]$ [ -d ~/.ssh ] || mkdir ~/.ssh
[awonder@whatever ~]$ chmod 0700 ~/.ssh
[awonder@whatever ~]$ [ -f ~/.ssh/authorized_keys ] || touch ~/.ssh/authorized_keys
[awonder@whatever ~]$ chmod 0600 ~/.ssh/authorized_keys
[awonder@whatever ~]$ cat id_rsa.pub >> ~/.ssh/authorized_keys

That’s it! Now you can delete the id_rsa.pub file on the server, it’s contents are in your authorized_keys file.

The next time you try to log in, it should ask you for your pass phrase rather than your password and let you connect in a much more secure way than using a password.

In the future, you can just install the same id_rsa.pub public key on any server you need to connect to via SSH and make password based authentication a thing of the past. This is much safer than password managers, by the way.

SSH Daemon Server Administration – Key Generation

The SSH keys a server uses to authenticate to a client should rarely be changed. They should be changed if the system was compromised or if the system is freshly installed. If you fire an administrator who had access to the keys, they also should be changed. If an administrator who had access to they keys leaves on good terms, it still is probably a good idea to change them. I also on my systems change them every two years just because.

Changing the keys will inconvenience users who need to connect, if just changing the keys because it has been two years, let the users know ahead of time.

Sometimes when a system is freshly installed, there was not enough entropy to generate quality keys. I suspect most distributions at this point do not have that issue, but suspecting is not secure.

On CentOS 7 systems there are three different keys to replace:

[root@host ~]# cd /etc/ssh
[root@host ssh]# tar -cf oldkeys.tar ssh_host*
[root@host ssh]# ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -b 4096 -t rsa

Generating public/private rsa key pair.
/etc/ssh/ssh_host_rsa_key already exists.
Overwrite (y/n)? y

Your identification has been saved in /etc/ssh/ssh_host_rsa_key.
Your public key has been saved in /etc/ssh/ssh_host_rsa_key.pub.
The key fingerprint is:
SHA256:o8eu5FdXuHQ2ujiTsfnkaP9Yfn5SABvspaMJTWPtNFk root@host
The key's randomart image is:
+---[RSA 4096]----+
|     * snip *    |
+----[SHA256]-----+

[root@host ssh]# ssh-keygen -f /etc/ssh/ssh_host_ecdsa_key -N '' -t ecdsa -b 521

Generating public/private ecdsa key pair.
/etc/ssh/ssh_host_ecdsa_key already exists.
Overwrite (y/n)? y

Your identification has been saved in /etc/ssh/ssh_host_ecdsa_key.
Your public key has been saved in /etc/ssh/ssh_host_ecdsa_key.pub.
The key fingerprint is:
SHA256:iYWUSY3FYXvYhfhA9ckFYBDQX5PjsDM7S0Eo3wZp52w root@host
The key's randomart image is:
+---[ECDSA 521]---+
|     * snip *    |
+----[SHA256]-----+

[root@host ssh]# ssh-keygen -f /etc/ssh/ssh_host_ed25519_key -N '' -t ed25519

Generating public/private ed25519 key pair.
/etc/ssh/ssh_host_ed25519_key already exists.
Overwrite (y/n)? y

Your identification has been saved in /etc/ssh/ssh_host_ed25519_key.
Your public key has been saved in /etc/ssh/ssh_host_ed25519_key.pub.
The key fingerprint is:
SHA256:vAljDx7qDJB+/TyOTzK3H3FlD1m55/L3dvPlmeQI8Vo root@host
The key's randomart image is:
+--[ED25519 256]--+
|     * snip *    |
+----[SHA256]-----+

[root@host ssh]# systemctl restart sshd.service

That’s it. Do it sparingly, your users will have to remove the old fingerprint from their clients and even though it is rather simple to do so, many have trouble understanding the concept.

SSH Port Selection

SSH uses TCP and listens on Port 22 by default. I personally change that.

You will hear a lot of people say that is security by obscurity. Pardon my language, but that’s fucking bullshit and they do not understand what security by obscurity means or the concept of why it should be avoided.

When you use a cipher to encrypt a message, guess what, that’s just a fancy way of saying you are obscuring the message. It is obscurity. Obscurity by itself is not a bad thing. It is a good thing. It makes it more difficult for the attacker to learn the secret you want to keep hidden.

Security by Obscurity is when you rely upon obscurity for your security. That is what is dangerous, not the obscurity itself.

If someone wants to target your server specifically, what port SSH is listening on does not matter, they will find it. Changing the port does nothing against a targeted attack. In that respect changing the port number does nothing for security. It does not reduce security, it just does nothing for it.

However the vast majority of attacks against SSH servers and I suspect the vast number of successful attacks against SSH servers are not targeted attacks. They are bots that scan the Internet looking for servers with Port 22 open and then attempt to brute force a login using common usernames and passwords. These bots are not going to portscan your server looking for an open SSH port, it simply is not worth their time. If your server is not listening on Port 22 they skip your server and go to the next, there are plenty of servers out there that do listen on Port 22.

Changing the port number thus greatly reduces the noise in your log files, and in the event that you do happen to have a user with a weak or commonly used password, the non-targeted attackers which are the majority of attackers will not exploit it because they do not bother to try to find what port SSH might be running on.

Of course it is better to just disable password based login over SSH but not every server can do that, and even if you do do that, the reduced noise in the system log is still worth it.

Please note that these attack bots are often smart enough to avoid reactive security tools like fail2ban. They often won’t pound your server with requests, they will only do a few requests at your server reducing the odds of an IP ban and then go on to the next server in their list and so on but they will come back to your server to try different combinations – often from a different IP address.

When I tried using fail2ban my logs were still filled with failed brute force attacks. When I switched to a high number port, failed login attempts ceased. Literally completely ceased. It is still possible for them to happen, but they just simply do not.

Port Selection

When selecting an alternative port, I recommend a high number port above 1024.

Again there are some who will disagree, pointing out that ports above 1024 do not require root access to open, allowing an attacker with shell access to potentially open such a port themselves.

First of all, SSH is a service that should always be running. An attacker with shell access on your system can not open the port you use while the SSH daemon is already running on the port. Either the attacker would need to a way to kill the SSH daemon or have to have a timed attack ready to grab the port during a period of time when it is down for maintenance.

Secondly, even if the first scenario does exist, the attacker will not be able to read the private keys is the /etc/ssh directory unless the attacker has root privilege. As such, the attacker can not create a trojan that would have a fingerprint that matches.

Thirdly if the attacker does have root access to read those private keys, then the port number doesn’t matter, the system is already p0wn3d.

Using a high number port puts it outside the realm of a typical port scan which usually only scans for ports below 1024 and well known ports above 1024.

Using a high number port that is not a well known port often used for something else means an attacker is likely to only know your SSH port if they specifically target your system. Most attackers do not.

Firewall

If you are running a firewall, you will need to poke a hole in it for the new port. Most distributions come with a firewall that if active, already has a hole poked for port 22.

With the firewall that ships with CentOS 7 (and is on by default with the CentOS 7 image currently provided by many VM hosts) you can poke a hole in the firewall using the following command:

[root@host ~]# /bin/firewall-cmd --zone=public --add-port=2112/tcp  --permanent
[root@host ~]# /bin/firewall-cmd --reload

Obviously change 2112 to whatever high number port you selected.

SELinux

If you have SELinux enabled, you need to let SELinux know that the ssh daemon will be using that port:

[root@host ~]# /usr/sbin/semanage port -a -t ssh_port_t -p tcp 2112

Again, obviously change 2112 to whatever high number port you selected.

Edit Configuration File

On CentOS 7 and every Linux distribution I have ever played with, the OpenSSH configuration file is located at /etc/ssh/sshd_config. In that file, change

#Port 22

to

Port 2112

Again, obviously change 2112 to whatever high number port you selected.

The change will not take effect until you restart the daemon. Users will have to specify your custom port when connecting, or their client will attempt to connect to port 22 and fail.

SSH Daemon Security Hardening

Changing the port is NOT a substitute for securing your SSH daemon configuration. Anyone who targets your system specifically will discover the port the daemon is running on.

Whether or not you changed the port number, the following changes either should be done or should at least be considered.

Disable Root User Login – MANDATORY ACTION

By default, the SSH daemon allows a remote connection by the root user. This is a dangerous default but a needed default, a fresh system needs to have a way for the system administrator to initially connect remotely and manage it. The assumption is made that a system administrator will disable root login during initial post install configuration.

In the SSH daemon configuration file (/etc/ssh/sshd_config) change

PermitRootLogin yes

to

PermitRootLogin no

That change will not take effect until you restart the SSH daemon.

Disable Password Authentication – OPTIONAL ACTION

By default, the SSH daemon allows users to connect using their password on the server for authentication.

Many system administrators (myself included) disable this, requiring users to use public key authentication as discussed earlier.

The advantage to disabling this, it prevents brute force attacks where the attacker tries to guess weak passwords from working. Password authentication simply ceases to work. You do not have to rely upon your users having strong passwords to prevent an attacker from possibly gaining shell access.

The disadvantage, sometimes you (the system administrator) will need to install a user’s public key for them so they can connect. On the one hand that is an inconvenience that takes us away from other things, but on the other hand it is our job and keeps the system secure.

If you wish to disable password based login, in the SSH daemon configuration file (/etc/ssh/sshd_config) change

#PasswordAuthentication yes

to

PasswordAuthentication no

That change will not take effect until you restart the SSH daemon.

Disable Challenge Response Authentication – MANDATORY ACTION

On CentOS 7, this is already disabled by default. On some distributions, it is not.

Unless you know you need this, you do not. It only works properly anyway when you have specifically set up a back-end for it. When you have not specifically set up a back-end for it, it will usually revert to using the username and password for the challenge / response even if you disabled password authentication.

Nutshell, if you do not have the back-end set up, it is redundant if password authentication is already allowed and it in practice overrides disabling of password authentication.

Shut it off unless you damn well know you need it.

On distributions where it is enabled, in the SSH daemon configuration file (/etc/ssh/sshd_config) change

#ChallengeResponseAuthentication yes

to

ChallengeResponseAuthentication no

That change will not take effect until you restart the SSH daemon.

Limit Key Exchange Protocols – OPTIONAL HIGHLY RECOMMENDED

Perfect Forward Secrecy is the concept that if the private key used by either server or client is ever captured, they can not be used by an attacker to decrypt passed encrypted sessions that were logged. Basically the private keys are only used for the two computers to authenticate each other, and then they negotiate a shared secret that is not easily discovered from the encrypted session itself.

There are two different types of key exchange that are typically used to obtain Perfect Forward Secrecy:

  1. DH (Diffie-Hellman)
  2. ECDH (Elliptical Curve DH)

The latter is conceptually superior but only when the parameters used to define the curve are safe. With many of the curves, the reason for some of the parameters selected has not been disclosed, and there is paranoia that their selection may have been influenced by the NSA due to known weaknesses. With Curve22519 we have full transparency in the selection of the parameters used to define the curve.

All SSH protocol 2 clients support DH with 2048-bit DH parameters. Almost all SSH protocol 2 clients support DH with 4096-bit parameters. Many SSH protocol 2 clients support ECDH with curve22519 but some do not (e.g. I believe OpenSSH in CentOS 6 does not).

It is therefore recommended to configure the SSH daemon to use curve22519 for the key exchange as the default but with a fallback to DH when the client does not support curve22519. To accomplish this, add the following line to the end of your SSH daemon configuration file (/etc/ssh/sshd_config):

KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256

That change will not take effect until you restart the SSH daemon.

DH Parameter Generation – OPTIONAL PARANOID PEDANTIC

The DH parameters that ship with OpenSSH are probably safe and are only used when the client does not support curve22519. That being said, they are a publicly known group and it possible the NSA or other state agencies have been studying them looking for a way to defeat the key exchange. By generating the parameters yourself, you will have DH parameter groups that are unique to your server.

This takes a couple of hours and probably is not necessary, but I do it.

For DH groups, I generate 2048-bit groups for the benefit of clients running on older hardware who have configured their clients to use 2048-bit parameters. I generate 4096-bit groups for the benefit of clients running on decent hardware. I do not generate groups larger than 4096-bit.

It is highly unlikely that key exchange even with 2048-bit groups can be cracked even by a state level attacker, it is inconceivable that key exchange with a 4096-bit group can be cracked. Larger groups just waste CPU resources, those clients paranoid enough to want something harder to crack than 4096-bit groups can update their clients to use curve25519 if they have not already.

When generating DH parameters while connected to your server over a network, it is highly recommended to use the screen utility, it takes a couple hours so there is a possibility of the connection being interrupted in the process. The screen utility allows the commands being run to continue if that happens.

To generate the custom parameters:

[root@host ~]# cd /etc/ssh
[root@host ssh]# ssh-keygen -G moduli-2048.candidates -b 2048
[root@host ssh]# ssh-keygen -T moduli-2048 -f moduli-2048.candidates
[root@host ssh]# ssh-keygen -G moduli-4096.candidates -b 4096
[root@host ssh]# ssh-keygen -T moduli-4096 -f moduli-4096.candidates

Run those commands one at a time and wait for a command to finish before starting the next.

The generation of 2048 bit parameters takes maybe 20 or 30 minutes, but the generation of 4096 parameters takes about two hours. Generating DH parameters for OpenSSH takes longer than for OpenSSL/LibreSSL due to how picky OpenSSH is.

You do not have to do it very often. In fact is probably safe to only do it once and forget about it.

Once they are finished:

[root@host ssh]# cp moduli moduli-backup-`date +%Y%m%d`
[root@host ssh]# cat moduli-2048 moduli-4096 > moduli

That replaces the default moduli with what was just generated.

Restart the SSH Daemon

After making whatever changes you decided to make, make sure to restart the SSH Daemon:

[root@host ~]# systemctl restart sshd.service
Anonymity protected with AWM Pluggable Unplugged