292

Most users would simply type ssh-keygen and accept what they're given by default.

But what are the best practices for generating ssh keys with ssh-keygen?

For example:

  • Use -o for the OpenSSH key format rather than the older PEM format (OpenSSH 6.5 introduced this feature years ago on 2014-01-30)

  • How should one calculate how many rounds of KDF to use with -a?

  • Should -T be used to test the candidate primes for safety? What -a value to use with this?

  • For the different key types, what are the recommended minimum -b bit sizes?

  • etc... (there are a mind-boggling set of options in the manual page).

6
  • 1
    (2) crypto.stackexchange.com/questions/40311/… (3) -T tests probable-primeness not 'safety'; you should never install a moduli file that isn't primes (4) for RSA at least 2048 maybe 3072; for DSA NIST requires group 2048 but also subgroup and hash 224+ and SSH can't handle the latter (yet?); for ECDSA the minimum possible 256 is fine; for Ed25519 there is no choice Commented Nov 24, 2016 at 6:18
  • Confusingly the manual explanation for -T is: Test DH group exchange candidate primes (generated using the -G option) for safety.. What is primes(4), and how does one translate this into something that can be typed at a command line (eg, in the RSA case)?
    – Tom Hale
    Commented Nov 24, 2016 at 7:26
  • 'primes' is the last word of my '(3)' about your third bullet and '(4)' is about your fourth bullet. Yes the man page for ssh-keygen is misleading; the page it links to for moduli(5) (that '(5)' meaning section 5 in the Unix man scheme) is better but still not exact. In short if you want to generate 'moduli' (really pairs of modulus and generator) always do -G THEN -T and use only the second result. It does produce 'safe' primes (p=2q+1) but 'safe' here is a historical relic, it is nonsmooth prime that matters. Commented Nov 24, 2016 at 9:13
  • Bleah! Of course no prime is smooth, and I meant DH wants prime with order of Zp* i.e. p-1 nonsmooth. While I'm at it, most of the mind-boggling options are about key import/export/conversion and file management and OpenSSH's idiosyncratic certs; the actual key (and even parameter) generation options in the program named keygen are relatively few. Commented Nov 26, 2016 at 7:55
  • 1
    Necroed: new keyfile format is the default (for all keytypes) since 7.8 in 2018-08 and -o is no longer needed (or documented) Commented Mar 22, 2021 at 3:32

3 Answers 3

300

This is still up to date as of July 2024. The OpenSSH defaults are safe to trust.


I recommend the Secure Secure Shell article, which suggests:

ssh-keygen -t ed25519 -a 100

Ed25519 is an EdDSA scheme with very small (fixed size) keys, introduced in OpenSSH 6.5 (2014-01-30) and made default ("first-preference") in OpenSSH 8.5 (2021-03-03). These have complexity akin to RSA at 4096 bits thanks to elliptic curve cryptography (ECC). The -a 100 option specifies 100 rounds of key derivations, making your key's password harder to brute-force.

In OpenSSH 9.0 (2022-04-08), OpenSSH also set its default key exchange method to hybrid Streamlined NTRU Prime + x25519 ("[email protected]"), noting:

The NTRU algorithm is believed to resist attacks enabled by future quantum computers and is paired with the X25519 ECDH key exchange (the previous default) as a backstop against any weaknesses in NTRU Prime that may be discovered in the future. The combination ensures that the hybrid exchange offers at least as good security as the status quo.

We are making this change now (i.e. ahead of cryptographically-relevant quantum computers) to prevent "capture now, decrypt later" attacks where an adversary who can record and store SSH session ciphertext would be able to decrypt it once a sufficiently advanced quantum computer is available.

Interest in Curve25519 spiked in 2013, when it was surmised that other standards may have been diluted. All modern systems now deploy Ed25519 for SSH, so you should no longer need to fall back to RSA (ssh-keygen -t rsa -b 4096 -a 100); the last Linux distributions to lack ed25519 support were Ubuntu 14.04 (support expired 2024-04-25) and RHEL/CentOS 6 ELS (support expired 2024-06-30).

Do not consider the other new ECC algorithm called ECDSA. It is considered suspect (it has known weaknesses and since the US government has been involved in its development, it may be compromised beyond that). Ed25519 was developed without any known government involvement.

Stay well away from DSA (“ssh-dss”) keys: they're not just suspect, DSA is insecure.

9
  • 1
    Another good thing to remember is that you can keep your rsa keys around until you migrate all your host systems to your new ed25519 public key. Put both in the agent, and the client/host will negotiate the best supported.
    – Raman
    Commented Jan 22, 2018 at 21:43
  • 2
    @juanmah – Yes, that's why I linked the Ed25519 adoption page and offered RSA 4096 as an alternative. That page points to Cyberduck for implementing Ed25519 on Azure (though that's presumably for Windows, not Linux). I'd assume you could upgrade OpenSSH on the Linux VM; the newer the better, but Ed25519 requires OpenSSH 6.5+. If you want a lightweight server, consider installing pts-dropbear.
    – Adam Katz
    Commented Mar 5, 2018 at 15:20
  • 4
    As of 7.8 about a month ago (see the first bullet) ssh-keygen writes 'new' format automatically, and if you want legacy format (for other than ed25519) you use -m PEM Commented Oct 2, 2018 at 1:00
  • 4
    @BasilBourque – It will prompt you for a passphrase. If you provide a passphrase on the command line like -N "secret pass phrase e>Q9= octet" then it's visible to other users on the system (e.g. ps auxww |grep keygen) and it is saved in your command history, so it's best to enter interactively.
    – Adam Katz
    Commented Jul 9, 2019 at 13:42
  • 3
    @JoãoPortela – I believe it is still current. As updated recently, OpenSSH now defaults to ed25519, so if you're on a recent version, this advice simply adds iteration rounds to protect the key's password (the default is currently 16).
    – Adam Katz
    Commented Mar 13, 2023 at 14:24
31

Most users would simply type ssh-keygen and accept what they're given by default.

Yes. To do a security for people, it needs to be simple. Therefore the default option should be safe, compatible and fast. You can provide alternatives, but default should be "good enough" for these who don't care. Therefore RSA (2048) in the old PEM format is the default at the moment.

  • Use -o for the OpenSSH key format rather than the older PEM format (OpenSSH 6.5 introduced this feature almost 3 years ago on 2014-01-30)

Three years is nothing. A lot of containers managed to evolve during these years, but SSH is here more than 20 years and still needs to deal with older clients. The new OpenSSH format is not widely adopted and supported yet.

  • How should one calculate how many rounds of KDF to use with -a?

Depends on the use case. Creating your key for your "stuff" repo on Github will be different than creating a keys in your favorite national agency as a certification authority or to access super-secret documents on dedicated server.

As pointed out, this is only for the new format, which is not yet widely used and it increases the time to decrypt key. The default number of rounds is 16 (would be nice to see it documented somewhere). More in the Cryptography question.

  • Should -T be used to test the candidate primes for safety? What -a value to use with this?

No. It is used for generating primes (/etc/ssh/moduli) for DH key exchange. It is not used in any way for generating SSH keys. How to generate and test the moduli file is explained in separate chapter MODULI GENERATION of manual page for ssh-keygen.

  • For the different key types, what are the recommended minimum -b bit sizes?

This is not SSH specific, but generally key sizes are recommended by NIST in this document, page 12 (per 2015):

RSA (2048 bits)
ECDSA (Curve P-256)

The Ed25519 does have fixed size so the -b parameter is ignored.

6
  • 6
    It is usually best practice to generate a key on the same system where you use it, so incompatibility between new file format and old software isn't a big problem. The algorithm (-t) is more often an issue: ed25519 keys won't interop with older versions, even ECDSA won't work with very old or RedHat-formerly-nobbled versions, while new versions reject DSA unless you tweak the configuration (there are already several Qs on that) -- so as you said we end up with RSA as the the works-everywhere choice. Commented Nov 26, 2016 at 8:02
  • 1
    Regarding protocols, my sshd_config man page says: The default is ‘2’. Protocol 1 suffers from a number of cryptographic weaknesses and should not be used. It is only offered to support legacy devices.
    – Tom Hale
    Commented Dec 7, 2016 at 23:25
  • Yes. I don't even think somebody would want to allow this protocol. It is not default on any of the current systems and there is no reason to allow it.
    – Jakuje
    Commented Dec 8, 2016 at 7:34
  • 1
    @TomHale update: protocol 1 (including rsa1 keys) was deleted at 7.6 in 2017-10 Commented Jan 14, 2022 at 23:54
  • Could you please update your link with the latest version. Am I right that the table on p55 now reccomends a RSA key length of 15360?
    – Tom Hale
    Commented Feb 6, 2022 at 3:27
17

Here's a one liner for Ed25519 based on recommended values: (without passphrase)

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -q -N ''

Another one for RSA:

ssh-keygen -t rsa -b 4096 -o -a 100 -f ~/.ssh/id_rsa -q -N ''

For adding to ssh agent automatically, you can use (RSA, no passphase):

keyname='secretKey' ; comment='[email protected]' ; ssh-keygen -t rsa -b 4096 -o -a 100 -f ~/.ssh/$keyname -q -N '' -C $comment ; eval `ssh-agent` ; ssh-add ~/.ssh/$keyname

From ssh-keygen Man page:

  • -a rounds: When saving a private key, this option specifies the number of KDF (key derivation function, currently bcrypt_pbkdf(3)) rounds used. Higher numbers result in slower passphrase verification and increased resistance to brute-force password cracking (should the keys be stolen). The default is 16 rounds.
  • -b bits: Specifies the number of bits in the key to create. For RSA keys, the minimum size is 1024 bits and the default is 3072 bits. Generally, 3072 bits is considered sufficient. DSA keys must be exactly 1024 bits as specified by FIPS 186-2. For ECDSA keys, the -b flag determines the key length by selecting from one of three elliptic curve sizes: 256, 384 or 521 bits. Attempting to use bit lengths other than these three values for ECDSA keys will fail. ECDSA-SK, Ed25519 and Ed25519-SK keys have a fixed length and the -b flag will be ignored.
  • -o : Save the private-key using the new OpenSSH format rather than the PEM format. This option doesn't appear anymore in the Man page, and thus it should be okay to be omitted.
  • -f filename: Specifies the filename of the key file.
  • -N: New passphrase
  • -q: Silence ssh-keygen
  • -t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa: Specifies the type of key to create.

Edit & disclaimer: To answer some comments, this answer focus on simplicity, and indicates explicitly that it's not using a passphrase for the key. the one liners above can be used in a non-interactive script to generate key pairs. If you don't like using an empty passphrase you can set one after -N option (be aware that it will be recorded to shell history), or set an environment variable that reads user input.

5
  • 17
    An empty passphrase is not a best practice. Yes, it is necessary for certain automated tasks, but those are exceptions. Your filenames are the defaults, making the use of -f output_keyfile unnecessary.
    – Adam Katz
    Commented Apr 11, 2018 at 18:34
  • 6
    Does -a 100 have any value at all with an empty passphrase? It seems that such a key is still trivially brute-forceable (try nothing -- and it works!) Commented Mar 13, 2019 at 3:45
  • 6
    Please explain why you would use -a with an empty passphrase. This seems senseless, but I may be uneducated in this regard. Commented Jul 9, 2019 at 0:21
  • 4
    I tested this by using -a 1000 -N '' and there was no delay. With -a 1000 -N 'x' there is a delay. Conclusion: -a with -N has no effect.
    – Tom Hale
    Commented Feb 6, 2022 at 3:05
  • 4
    Please add -C <comment> to add the service name that this key is being generated for... because [best practice] we all generate different keys for each service, right?
    – Tom Hale
    Commented Feb 6, 2022 at 3:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .