Matching a private key to a public key

If you do much work with SSL or SSH, you spend a lot of time wrangling certificates and public keys. Public key cryptography provides the underpinnings of the PKI trust infrastructure that the modern internet relies on, and key management is a big part of making that infrastructure work. If you do any work on the web, you deal with public keys. As keys age and things get shuffled around, though, you may often find yourself (as do I) trying to figure out which private keys go with which public keys. That can sometimes turn out to be a bit tricky, though, since exactly how to do that depends on both the format of the key files themselves as well as the public key cryptography algorithm in use. I've put together a quick reference here for anybody (including myself) who's faced with the same problem.

SSL

SSL presents public keys in the context of an X.509 certificate, which itself includes a lot of information about the principal identified by the public key as well as its own digital signature, signed by yet another keypair. You can create a minimal X.509 certificate using openssl as in:

$ openssl req -x509 -newkey rsa:512
Generating a 512 bit RSA private key
.++++++++++++
....++++++++++++
writing new private key to 'privkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Texas
Locality Name (eg, city) []:Dallas
Organization Name (eg, company) [Internet Widgits Pty Ltd]:JoshCo
Organizational Unit Name (eg, section) []:Security
Common Name (e.g. server FQDN or YOUR name) []:Joshua Davies
Email Address []:joshua.davies.tx@gmail.com

Example 1: Create a minimal keypair using openssl

By default, this will print the actual certificate, in PEM-format, to stdout and save the private key (also in PEM-format) in a file named privkey.pem. Figure 1 shows a pair of these as they might appear in your filesystem.

$ cat cert.pem
-----BEGIN CERTIFICATE-----
MIICdTCCAh+gAwIBAgIJALVW/bwAH0sQMA0GCSqGSIb3DQEBCwUAMIGVMQswCQYD
VQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxDzANBgNVBAcMBkRhbGxhczEPMA0GA1UE
CgwGSm9zaENvMREwDwYDVQQLDAhTZWN1cml0eTEWMBQGA1UEAwwNSm9zaHVhIERh
dmllczEpMCcGCSqGSIb3DQEJARYaam9zaHVhLmRhdmllcy50eEBnbWFpbC5jb20w
HhcNMTYwNzIwMTkzNTM5WhcNMTYwODE5MTkzNTM5WjCBlTELMAkGA1UEBhMCVVMx
DjAMBgNVBAgMBVRleGFzMQ8wDQYDVQQHDAZEYWxsYXMxDzANBgNVBAoMBkpvc2hD
bzERMA8GA1UECwwIU2VjdXJpdHkxFjAUBgNVBAMMDUpvc2h1YSBEYXZpZXMxKTAn
BgkqhkiG9w0BCQEWGmpvc2h1YS5kYXZpZXMudHhAZ21haWwuY29tMFwwDQYJKoZI
hvcNAQEBBQADSwAwSAJBAL1gA6M44JQtAZPx/VV0YOV8xZfDzEZQ7fe/jDc5k94H
AVMxx1nPm1cvIgEIdP0ElOsF1qNVBUgcBALZYwz95usCAwEAAaNQME4wHQYDVR0O
BBYEFODCDj93XQvkv9TsqYAda+Z2ML41MB8GA1UdIwQYMBaAFODCDj93XQvkv9Ts
qYAda+Z2ML41MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADQQByknlBVPTY
fnNgZZAcUyXEp7YnUtZR5VmHDpRcto3d6a8jhW1C+xNaUwEZOoeDYQuYNfWtixyE
INtseySuRB8x
-----END CERTIFICATE-----
$ cat privkey.pem
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQImfM5LlHUgm4CAggA
MBQGCCqGSIb3DQMHBAg/m4N5AvuKaQSCAWCTzt/NpYbP9PgtF0fw4j9NSTCQgUHk
1Ukdr4PXZ8/512lBC1+bR5oppgBehkCZUCm+gM0/ZyOU+oNo1kyiO4tCohE2Z98X
tzjjqRbMnF9Mrqrw0MIbue5e+QbggyVDaSV1VcwcOOdsyOw5zfkBsaBjQhLQaQ7m
lZcAsMfwaGuLOWd+tL5Ee6o1BVx9UiHFzBG4s9E5MWrIRraZQBOo23cWe9ztygUP
zwhyZv0GznDRamlwLxPQbMda9ucswft1N8nlu1vEpvw38/GSyXX6kvBpy4L68DIy
H67XAgHvmr2bDgZFfmYaqmJw9mU5ZGPbc5QN3SP9cgASxRZPaRL7kCT5Cn04Yy1y
oOmH6K/oCPqu0cJYvnaNPiKqpBpPpwb9+xcrIPVwD+2yAdExpxUGWNGz4puZVBRm
rBV0Nnc107vHfu1Qq2/lEMpYlggF3oxXu+Z1MvSbC3V3OUcKAExQ0iJI
-----END ENCRYPTED PRIVATE KEY-----

Figure 1: Public/private keypair

You know that the keys in figure 1 go together because I've shown them that way, but I've lost sight of how many times I've found two similarly-named files whose contents were suspicious: how can one go about ensuring (or determining conclusively otherwise) that a private key file corresponds to a given public key file (aka certificate)?

Now, a quick glance at these and you might notice that they both begin with MII and assume that may be a clue that they're related. Unfortunately, it's not that easy: all certificates and certificate related files start with MII because that's the standard ASN.1 leader. What you see here are Base64 encoded representations of ASN.1 encoded binary data - some of which represent key material and some of which represent subject data. I won't go into the details of ASN.1 here (for a full explanation, see chapter 5 of Implementing SSL), but I will show you how you can use available tools to extract the relevant bits of information to find the actual keying material itself.

However, there are currently three public-key cryptography methods currently in popular use, and how and where to look to match private keys depends on which public key algorithm was used to generate the keys to begin with. As it turns out, openssl doesn't actually provide tools that make it easy to figure out which algorithm was in use (even though this information is available in the certificate itself), so your best bet in this case is to try each one until you get a "hit".

RSA Public Keys

As of the time of this writing, the RSA algorithm is still the default public key generation algorithm for openssl. That is, if you don't specify an alternative, you'll get an RSA key. RSA stands for "Rivest, Shamir and Adelman" (the names of the three researchers who discovered it) and is actually pretty easy to understand: the public key is two numbers (traditionally labelled e and n) and the private key is another number (traditionally labelled d) that are related such that any number (me)d)%n=m. This is secure because discrete exponentiation is computationally feasible whereas computing a discrete logarithm is not. As it turns out, e and n are included in the public key (certificate) file and d and n are included in the private key file: therefore, to determine if the key files are related, check the n's and, if they match, the files are two halves of the same key.

You can use openssl to print out both values as shown in example 2:

$ openssl x509 -in cert.pem -noout -modulus
Modulus=BD6003A338E0942D0193F1FD557460E57CC597C3CC4650EDF7BF8C373993DE07015331C759CF9B572F220108
74FD0494EB05D6A35505481C0402D9630CFDE6EB
$ openssl rsa -in privkey.pem -noout -modulus
Enter pass phrase for privkey.pem:
Modulus=BD6003A338E0942D0193F1FD557460E57CC597C3CC4650EDF7BF8C373993DE07015331C759CF9B572F220108
74FD0494EB05D6A35505481C0402D9630CFDE6EB

Example 2: print out moduli

These are printed in hexadecimal format and represent very long numbers: if you hear somebody talking about, say, a 2,048-bit RSA key, they're referring to the length of the modulus. If you're the very, very cautious type, you can compare them character-for-character, but I usually just glance at the first few and last few bytes.

DSA Public Keys

Maybe because it's the default, or maybe because it's the easiest to understand, RSA is still by far the most popular public-key algorithm in use, even today. However, since the first release of SSL, there was an alternative public key algorithm available: DSA.

One possible reason for the inclusion of DSA in SSL/TLS is that it was, at the time, the U.S. government standard: DSA just stands for Digital Signature Algorithm. Another possible reason is that its create, Dr. Taher Elgamal, was also the original creator of the SSL protocol. RSA has a technical advantage over DSA: by its nature, it can be used both to encrypt data — say, for a key exchange — as well as digitally sign data. However, this is only a slight technical edge, since when RSA is used for key exchange, the compromise of a private key can subsequently be used to decrypt any previously intercepted traffic. For this reason, it's recommended to use the perfect forward secrecy afforded by Diffie-Hellman key exchanges even when you have an RSA key.

DSA is a bit more complex than RSA, but is based on the same computational infeasibility of computing discrete logarithms. DSA requires that you generate three numbers (traditionally labelled g, p, q) which are not secret, and a pair of numbers x and y related such that y = gx % p (q is used during the signature generation and verification process and is related to g and p. Again, for full details, refer to my book). x is the private key and y is the public key.

If you want to create a DSA keypair with openssl, you must first generate the DSA parameters g, p and q as shown in example 3.

$ openssl dsaparam 1024
Generating DSA parameters, 1024 bit long prime
This could take some time
.........................+..................+++++++++++++++++++++++++++++++++++++++++++++++++++*
+.+...+..........+.+.....+....................................+...........+....+..............+.
.................+........+.........+.+...+..........................+..........................
.....................+.................+.+....+.....+..+......+.........+........+..............
...............+......+.......+...........................+....+..........................+.....
...............+......+.......................+.+.............................+....+.......+....
..+.....+......+.......+..+.+++++++++++++++++++++++++++++++++++++++++++++++++++*
-----BEGIN DSA PARAMETERS-----
MIIBHgKBgQD+Jqc6n8hRY2vOSSfZ60TgiiuwvZOixpitX01yoIwMyDz3Zh4wRCzD
ZZZpOIDAAcQ9DT9yHMqMndFFYIhhnRodyvIp5FzJmb77SEzz4LJTnKR2syekIZHb
8yLyDJQKZ0IHtFdu7kx91hjJSZ5r27uzvkOvB4m6t4fpxrhWFrN/YQIVAOvXzj8q
M2Dq5tg6L4xSZqWgpmRRAoGAOdNQ+tZnFCFiPthvLj2XSh2WJb9yu1eofHroi+M8
ZLA2654tLt+LXVkZsRmIQx+eMz/qcjjBkLYGZcZ/t3gcDmt0+R3KKfXCQuJC0+5G
nt2Mjk1d/f5mi0ekCRaIWABluCBTzIiKA9wBEnZ+8dyjMqVK7nsgINc1N6LrS6GE
YVk=
-----END DSA PARAMETERS-----

Example 3: Create DSA parameters

This is a direct ASN.1 encoding of g, p and q: you can see the actual numbers if you save the parameters to another file and use the dsaparam subcommand of openssl as shown in example 4:

$ openssl dsaparam -in dsaparam.pem -noout -text
    P:   
        00:fe:26:a7:3a:9f:c8:51:63:6b:ce:49:27:d9:eb:
        44:e0:8a:2b:b0:bd:93:a2:c6:98:ad:5f:4d:72:a0:
        8c:0c:c8:3c:f7:66:1e:30:44:2c:c3:65:96:69:38:
        80:c0:01:c4:3d:0d:3f:72:1c:ca:8c:9d:d1:45:60:
        88:61:9d:1a:1d:ca:f2:29:e4:5c:c9:99:be:fb:48:
        4c:f3:e0:b2:53:9c:a4:76:b3:27:a4:21:91:db:f3:
        22:f2:0c:94:0a:67:42:07:b4:57:6e:ee:4c:7d:d6:
        18:c9:49:9e:6b:db:bb:b3:be:43:af:07:89:ba:b7:
        87:e9:c6:b8:56:16:b3:7f:61
    Q:   
        00:eb:d7:ce:3f:2a:33:60:ea:e6:d8:3a:2f:8c:52:
        66:a5:a0:a6:64:51
    G:   
        39:d3:50:fa:d6:67:14:21:62:3e:d8:6f:2e:3d:97:
        4a:1d:96:25:bf:72:bb:57:a8:7c:7a:e8:8b:e3:3c:
        64:b0:36:eb:9e:2d:2e:df:8b:5d:59:19:b1:19:88:
        43:1f:9e:33:3f:ea:72:38:c1:90:b6:06:65:c6:7f:
        b7:78:1c:0e:6b:74:f9:1d:ca:29:f5:c2:42:e2:42:
        d3:ee:46:9e:dd:8c:8e:4d:5d:fd:fe:66:8b:47:a4:
        09:16:88:58:00:65:b8:20:53:cc:88:8a:03:dc:01:
        12:76:7e:f1:dc:a3:32:a5:4a:ee:7b:20:20:d7:35:
        37:a2:eb:4b:a1:84:61:59

Example 4: View DSA parameters

And you can request a new DSA keypair as shown in example 5.

$ openssl req -x509 -newkey dsa:dsaparam.pem 
Generating a 1024 bit DSA private key
writing new private key to 'privkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Texas
Locality Name (eg, city) []:Dallas
Organization Name (eg, company) [Internet Widgits Pty Ltd]:JoshCo
Organizational Unit Name (eg, section) []:Security
Common Name (e.g. server FQDN or YOUR name) []:Joshua Davies
Email Address []:joshua.davies.tx@gmail.com
-----BEGIN CERTIFICATE-----
MIIDvDCCA3mgAwIBAgIJANxvSOphtH76MAsGCWCGSAFlAwQDAjCBlTELMAkGA1UE
BhMCVVMxDjAMBgNVBAgMBVRleGFzMQ8wDQYDVQQHDAZEYWxsYXMxDzANBgNVBAoM
Bkpvc2hDbzERMA8GA1UECwwIU2VjdXJpdHkxFjAUBgNVBAMMDUpvc2h1YSBEYXZp
ZXMxKTAnBgkqhkiG9w0BCQEWGmpvc2h1YS5kYXZpZXMudHhAZ21haWwuY29tMB4X
DTE2MDcyMDIwNTEyOVoXDTE2MDgxOTIwNTEyOVowgZUxCzAJBgNVBAYTAlVTMQ4w
DAYDVQQIDAVUZXhhczEPMA0GA1UEBwwGRGFsbGFzMQ8wDQYDVQQKDAZKb3NoQ28x
ETAPBgNVBAsMCFNlY3VyaXR5MRYwFAYDVQQDDA1Kb3NodWEgRGF2aWVzMSkwJwYJ
KoZIhvcNAQkBFhpqb3NodWEuZGF2aWVzLnR4QGdtYWlsLmNvbTCCAbYwggErBgcq
hkjOOAQBMIIBHgKBgQD+Jqc6n8hRY2vOSSfZ60TgiiuwvZOixpitX01yoIwMyDz3
Zh4wRCzDZZZpOIDAAcQ9DT9yHMqMndFFYIhhnRodyvIp5FzJmb77SEzz4LJTnKR2
syekIZHb8yLyDJQKZ0IHtFdu7kx91hjJSZ5r27uzvkOvB4m6t4fpxrhWFrN/YQIV
AOvXzj8qM2Dq5tg6L4xSZqWgpmRRAoGAOdNQ+tZnFCFiPthvLj2XSh2WJb9yu1eo
fHroi+M8ZLA2654tLt+LXVkZsRmIQx+eMz/qcjjBkLYGZcZ/t3gcDmt0+R3KKfXC
QuJC0+5Gnt2Mjk1d/f5mi0ekCRaIWABluCBTzIiKA9wBEnZ+8dyjMqVK7nsgINc1
N6LrS6GEYVkDgYQAAoGAFPTNpgyJLOEjqvvBqGnFzYKRy4C9Hi7l2Mlp1CMBQsnQ
UmF/iMQzacm+YRf0dftK605UA5NweImdJu03Vz//3hNUw4LDVwjCJ/LbffZPbZaq
HAJgoFVaDxnnaRCc7FVMavY7Mk3GSSqEQTOg9sGoPel5iE+lwINPnDYd8kO13Waj
UDBOMB0GA1UdDgQWBBQz7mchcS8GqD6S0SG4hBt5q6Ua+DAfBgNVHSMEGDAWgBQz
7mchcS8GqD6S0SG4hBt5q6Ua+DAMBgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgMw
ADAtAhQw8YSNMe/y9cTnLI01WjdWKQwsvwIVAIcWDfcLR7VWN7q50LFz7U51HDNw
-----END CERTIFICATE-----

Example 5: Generate DSA certifiate

Recall from Example 2 that you can compare the moduli of the private and public keys in an RSA certificate to verify that they are equivalent. There is a modulus associated with DSA: it's the number p that was created by the call to dsaparams. However, if you ask for the modulus of a DSA certificate as in example 2, you won't get the p value, instead you'll get the public key y. Likewise, if you ask for the modulus of the private key file, you'll see the same y value. So you can actually verify that a DSA private key fits with a DSA public key using the same sequence of commands you used to verify RSA keys, as shown in example 6. The only difference is that you must use the dsa subcommand instead of the rsa subcommand to see the modulus in the private key.

$ openssl x509 -in cert.pem -noout -modulus
Modulus=14F4CDA60C892CE123AAFBC1A869C5CD8291CB80BD1E2EE5D8C969D4230142C9D052617F88C43369C9BE6117
F475FB4AEB4E5403937078899D26ED37573FFFDE1354C382C35708C227F2DB7DF64F6D96AA1C0260A0555A0F19E76910
9CEC554C6AF63B324DC6492A844133A0F6C1A83DE979884FA5C0834F9C361DF243B5DD66
$ openssl dsa -in privkey.pem -noout -modulus
read DSA key
Enter pass phrase for privkey.pem:
Public Key=14F4CDA60C892CE123AAFBC1A869C5CD8291CB80BD1E2EE5D8C969D4230142C9D052617F88C43369C9BE6
117F475FB4AEB4E5403937078899D26ED37573FFFDE1354C382C35708C227F2DB7DF64F6D96AA1C0260A0555A0F19E76
9109CEC554C6AF63B324DC6492A844133A0F6C1A83DE979884FA5C0834F9C361DF243B5DD66

Example 6: Verify that a DSA private key corresponds to a DSA publc key

The only issue you're likely to run into here is that there's no easy way, unless the creator of the key named the file specifically, to tell if a private key is a DSA key or an RSA key. The easiest way to check is to try to parse it as an RSA key as shown in example 2 and, if you get an error such as "digital envelope routines:EVP_PKEY_get1_RSA:expecting an rsa key:p_lib.c:279:", try it as a DSA key.

ECDSA Public Keys

The algorithm that I briefly described in the previous section got the designation DSA before researchers discovered that there was another, more secure, way to do essentially the same thing. In this case, though, rather than relying on the computational infeasibility of the discrete logarithm problem, they relied instead on the computational infeasibility of elliptic curve division. Since the name "DSA" was already taken, they named this ECDSA to distinguish it from "classic" or "discrete logarithm" DSA. In essence, the algorithm is the same: public and private keys are computed the same way, and ECDSA depends on some preset parameters, but elliptic curve multiplications are performed rather than modular exponentiations.

DSA never really caught on with the SSL-using public, but ECDSA is starting to become popular: one of the issues with discrete logarithm public-key algorithms is that there's never really been a formal mathematical proof of their security. We know that a 1024-bit key is more secure than a 512-bit key, but we don't really know just how much more secure. The nature of elliptic curves allows us to rigorously validate that every bit of the key contributes equally to the security of the signature: hence, adding one more bit to the length of the key demonstrably doubles the security provided by it.

For this reason, ECDSA keys can be much smaller than RSA or DSA keys and provide the same security. Plus, "elliptic curve" just sounds cool, and who doesn't want to use a cool-sounding public key algorithm?

Just as with DSA, you have to explicitly ask OpenSSL for ECDSA, and you have to start by creating a parameter file. For Elliptic Curve Cryptography (ECC), the parameters are not numbers g, p and q but instead a specification of an elliptic curve of the form y2=x3+ax+b. The security of ECC depends quite a bit on how the parameters a and b are determined, so there are quite a few named curves that almost everybody uses: the easiest way to create a reasonably secure EC parameter file, then is to use one of those named curves like everybody else as shown in example 7.


$ openssl ecparam -name prime192v1
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBAQ==
-----END EC PARAMETERS-----

Example 7: Generate an EC parameter file using a named curve

You can see that this is quite a bit shorter than DSA parameters. The BggqhkjOPQMBAQ== is a Base64 encoded representation of the ASN.1 encoding of the compressed 7-byte Object Identifier 1.2.840.10045.3.1.1: the ANSI designation of the ANSI standard Elliptic curve secp192r1. Fortunately, you don't need to understand any of that to use ECDSA.

Armed with an ECC parameter file, you can then create an ECDSA certificate as shown in example 8.

$ openssl req -x509 -newkey ec:ec.param

Example 8: Create an ECDSA certificate

This is reminiscent of the DSA certificate creation process: you tell OpenSSL that you want an ECDSA key and you give it a parameter file indicating which curve you'd like to use. The private key is a single number by which the point should be "multiplied" (in the somewhat funky way ECC defines Elliptic Curve multiplication) and the public key is that point multiplied by that number.

Recall from examples 2 and 6 that, if you want to compare the public key contained in an RSA or a DSA certificate against a potential private key, you ask to see the -modulus. If you try this on an ECDSA certificate, though, you'll just get back the error message "Modulus=Wrong Algorithm type". Instead, where ECDSA is in use, you can output the entire key in PEM format as shown in example 9:

$ openssl x509 -in cert.pem -noout -pubkey
-----BEGIN PUBLIC KEY-----
MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAESve6BpTMK8t/Hk1gBhJznwxNvZXT
3hA4Jk9IhGq9MCXEgINrjxWiy2mCM9Vxc1v4
-----END PUBLIC KEY-----

Example 9: Print out an ECDSA public key from its certificate

This can be matched against the private key by asking the private key file to output just the public key portion as in example 10.

$ openssl ec -in privkey.pem -pubout
read EC key
Enter PEM pass phrase:
writing EC key
-----BEGIN PUBLIC KEY-----
MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAESve6BpTMK8t/Hk1gBhJznwxNvZXT
3hA4Jk9IhGq9MCXEgINrjxWiy2mCM9Vxc1v4
-----END PUBLIC KEY-----

Example 10: Print out an ECDSA public key from its private key

You can do this with RSA and DSA keys as well, actually: you can request -pubout from the certificate and private key files and see the full Base64-encoded ASN.1 representation of the public key, but you still have to use the correct "subcommand" rsa or dsa. Since the modulus is shorter and easier to compare, I prefer to view it when dealing with RSA keys, but if you prefer to be more consistent, you can use the same sequence with all three public key algorithms, remembering to switch out the subcommand when dealing with the key.

Again, there are generally no hints from the certificate file or file name that you're looking at an ECDSA certificate; you can either print out the whole certificate content with the -text option of x509 or just try RSA, DSA and ECDSA options in that order until you find one that outputs meaningful data.

SSH

Conceptually, SSH and SSL are very similar. There's been a (very) slow-moving effort to consolidate file formats between SSH and SSL, but for the most part, you can count on slightly incompatible formats between the two. I'll walk through the key creation process and the subsequent comparison process for each of the algorithms below, but I'll assume you've had a chance to review the overviews above (or that you already know the difference between RSA, DSA and ECDSA).

SSH does not normally use certificates to contain public keys; instead, the identity associated with a public key is determined by its location in the file system (i.e. whose home directory it's installed in). Thus, the public key definition is much more compact. In all cases, key generation is performed using the ssh-keygen command, and the -t parameter specifies the public key algorithm to use. Fortunately for us, SSH is a lot more consistent with regards to public/private key matching: you can always see the public key parameter -y to see the public key that corresponds with a private key regardless of the algorithm, as I'll demonstrate below.

RSA

RSA is the default; if you leave off the -t parameter, you'll get an RSA key. I've shown the (redundant) -t rsa option in example 11, though, for the sake of consistency.

$ ssh-keygen -t rsa -f rsakey
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in rsakey.
Your public key has been saved in rsakey.pub.
The key fingerprint is:
SHA256:LopAFbpSOTGqWA4tbgAjWEGOPjdPYEIdO8ppC9XJeBc jdavies@localhost
The key's randomart image is:
+---[RSA 2048]----+
|=+B+. E          |
|=*.Oo. .         |
|*oX*= .          |
|BBBoo.           |
|=%.o .  S        |
|* + +  .         |
|..   .. .        |
| . . . .         |
|  . .            |
+----[SHA256]-----+
$ ls
rsakey      rsakey.pub

Example 11: Generate an RSA SSH keypair

As you can see, the output is a couple of files. Unlike OpenSSL, SSH does not, by default, encrypt the private key: it's up to you, the user, to take advantage of the underlying OS security mechanisms (e.g. chmod 600 rsakey) to secure it. There's also, by default, an SHA2 fingerprint as well as a randomized ASCII-art image: the idea behind this is that the user should memorize his public key's associated image and recall it on each login. I'd be curious to know if anybody actually does take advantage of this.

The public key is in an SSH-specific file format as shown in example 12.

$ cat rsakey.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsg0yBBuSkiE+4kTwaOLxjjbZktM6nD1Mt6nqUvAcZHqlJD0+vqRsJOzsl
FXE0hcA0lHURh4OYnCjPqvWLvYYa37amKDmS+3xManrmlyn2lRt2tLAV1L7sSjGL6dxsO8I/DKI87Yc9VLemAHlGyZdDqkiU
0Caa+dWT/bntCGyxfedjqykL5nHyntCjFxuyvlI4dqZA7MnW1jxKMMra7kbk3701MfNf9r42Ki+0Aj9M4dS7mIrjYGmPlgW/
R9wk/+Bhyj3HfZRtwrLWq199+GJseCKVHUgPEUKfgkge2ojHQzV7V4AxknH0i9IXjL5Qyx8c61PLTChG/SLlUgNGjSNX jdavies@localhost

Example 12: RSA public key format

You've probably correctly guessed that the middle token in the public key file is a Base-64 encoded representation of a public key. The first token, ssh-rsa and the last, jdavies@localhost are purely informational and not used by SSH itself; they're hints to you, the user, as to what sort of key this is and who it's for.

"But wait," you may be saying, "Didn't you say earlier that Base64 public key files all started with MII?" And I did say that, and it was true — at least of Base64 X.509 ASN.1 encoded certificates (like the ones that OpenSSL works with). SSH, on the other hand, deals in "raw" public keys: what you're looking at in example 12 is the base64 encoded representation of the raw binary public key values (e and n) with a prepended informational header.

The private key file, on the other hand, is in the same format as OpenSSL's RSA private key: in fact, you can use OpenSSL to parse and output the details of an SSH private key. However, if you just want to validate that a given RSA SSH private key matches a public key, you can take advantage of the -y option of ssh-keygen as shown in example 13. This outputs the entire public key — SSH does not, unfortunately, make it easy to view just the modulus value (which is, strictly speaking, the only thing you must know to match an RSA private key to a public key).

$ cat rsakey.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsg0yBBuSkiE+4kTwaOLxjjbZktM6nD1Mt6nqUvAcZHqlJD0+vqRsJOzsl
FXE0hcA0lHURh4OYnCjPqvWLvYYa37amKDmS+3xManrmlyn2lRt2tLAV1L7sSjGL6dxsO8I/DKI87Yc9VLemAHlGyZdDqkiU
0Caa+dWT/bntCGyxfedjqykL5nHyntCjFxuyvlI4dqZA7MnW1jxKMMra7kbk3701MfNf9r42Ki+0Aj9M4dS7mIrjYGmPlgW/
R9wk/+Bhyj3HfZRtwrLWq199+GJseCKVHUgPEUKfgkge2ojHQzV7V4AxknH0i9IXjL5Qyx8c61PLTChG/SLlUgNGjSNX jdavies@localhost
$ ssh-keygen -y -f ./rsakey
Enter passphrase: 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsg0yBBuSkiE+4kTwaOLxjjbZktM6nD1Mt6nqUvAcZHqlJD0+vqRsJOzsl
FXE0hcA0lHURh4OYnCjPqvWLvYYa37amKDmS+3xManrmlyn2lRt2tLAV1L7sSjGL6dxsO8I/DKI87Yc9VLemAHlGyZdDqkiU
0Caa+dWT/bntCGyxfedjqykL5nHyntCjFxuyvlI4dqZA7MnW1jxKMMra7kbk3701MfNf9r42Ki+0Aj9M4dS7mIrjYGmPlgW/
R9wk/+Bhyj3HfZRtwrLWq199+GJseCKVHUgPEUKfgkge2ojHQzV7V4AxknH0i9IXjL5Qyx8c61PLTChG/SLlUgNGjSNX

Example 13: Verfiy an SSH RSA private key matches a public key

Everything up to the "comment" at the end of the public key will match if this is the correct private key. This flag is so convenient you may see fit to overlook the impropriety of using a command whose name ends in "keygen" to do something besides generating keys.

DSA

While SSL requires that DSA certificates (and, by extension, DSA public keys) be created in two steps — DSA parameter generation followed by key generation — ssh-keygen will go ahead and do both on your behalf, as shown in example 14.

$ ssh-keygen -t dsa -f dsakey
Generating public/private dsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in dsakey.
Your public key has been saved in dsakey.pub.
The key fingerprint is:
SHA256:cW3FtUNZj0f4ZI+4xnYPQjJVfYxX93/ESl1qtdYav7U jdavies@localhost
The key's randomart image is:
+---[DSA 1024]----+
|             ooB%|
|           ...=O/|
|        . ..o.*@@|
|         oo.oooB=|
|        S  = .o =|
|            * o =|
|           o o E |
|                .|
|                 |
+----[SHA256]-----+

Example 14: Create a DSA keypair using ssh-keygen

And, as shown in example 15, you can use the -y option in exactly the same way for a DSA key as for an RSA key: you don't even have to know which format the key is in (although the opening few characters of the public key file are a reminder).

$ cat dsakey.pub 
ssh-dss AAAAB3NzaC1kc3MAAACBAJIwBdSPG6YdLyqrTrUh64GK//2He3cUxFWXzTN14UtVZH66dHlFtlaWHStEvToofWfQ
A3ZokA/VC4YeGbJFrjjTs8WRBEzxtIoT59vLXKdNbX7Ik3/J8KGFcKDa5cqb/RuHoP4Fh6gf2OIeMIbaVKDIuqpfrflbLcfI
DdICDqMjAAAAFQCTFDG+X3fgtv6ebNUPvGYFxlNh2wAAAIApCUsRy/ZUNkRgv/VsIoDLA2TvnQYko73b4w1igrCfQtjYPLW2
/rz4nRvfEDZfvKYIuCPizPDcaA8qBScao6Xgvs536ywlc5e5SVEtol2bjaJzS2nMJzrue2UGteSOMnVpQ0rDklwce3hWv9dW
/Rs9KuWAGSMK9uzF4bC/BkOSxQAAAIALhKtOSPwrq/Kct/GcyRL78MZtvOa/O5AWTUzMI1tlj46Pj80JxDxUpPdRxECI7zxy
miL/ySBOryyDJBjzIrMIYzX4hXqS8+XHHixH0kk9slF1o89udRHF7HtOcfs/Ot7JWO+ma7JGqXfDVEacUS9PuwuKQyDeEMIj
e4mcacghaQ== jdavies@localhost
$ ssh-keygen -y -f dsakey
Enter passphrase: 
ssh-dss AAAAB3NzaC1kc3MAAACBAJIwBdSPG6YdLyqrTrUh64GK//2He3cUxFWXzTN14UtVZH66dHlFtlaWHStEvToofWfQ
A3ZokA/VC4YeGbJFrjjTs8WRBEzxtIoT59vLXKdNbX7Ik3/J8KGFcKDa5cqb/RuHoP4Fh6gf2OIeMIbaVKDIuqpfrflbLcfI
DdICDqMjAAAAFQCTFDG+X3fgtv6ebNUPvGYFxlNh2wAAAIApCUsRy/ZUNkRgv/VsIoDLA2TvnQYko73b4w1igrCfQtjYPLW2
/rz4nRvfEDZfvKYIuCPizPDcaA8qBScao6Xgvs536ywlc5e5SVEtol2bjaJzS2nMJzrue2UGteSOMnVpQ0rDklwce3hWv9dW
/Rs9KuWAGSMK9uzF4bC/BkOSxQAAAIALhKtOSPwrq/Kct/GcyRL78MZtvOa/O5AWTUzMI1tlj46Pj80JxDxUpPdRxECI7zxy
miL/ySBOryyDJBjzIrMIYzX4hXqS8+XHHixH0kk9slF1o89udRHF7HtOcfs/Ot7JWO+ma7JGqXfDVEacUS9PuwuKQyDeEMIj
e4mcacghaQ==

Example 15: Match a pair of DSA SSH keys

This is all identically true of ECDSA; I won't repeat it here.

EdDSA

SSH supports one additional public key signature method that SSL does not, EdDSA. Actually, EdDSA is a more specific variant of the very generic ECDSA, hyperoptimized for speed and stronger security, but specific enough that it warrants its own generation commands. You can still use ssh-keygen -y to compare the keys; the key type will be listed as ssh-ed25519, a specific EdDSA curve.

Add a comment:

Completely off-topic or spam comments will be removed at the discretion of the moderator.

You may preserve formatting (e.g. a code sample) by indenting with four spaces preceding the formatted line(s)

Name: Name is required
Email (will not be displayed publicly):
Comment:
Comment is required
Julien, 2018-07-11
Thanks ! that is really detailled journey into certificates content and RSA keys !

From here I continued my journey by diving deep into RSA, up to the Modular exponentiation.
Amazing how the calculus effort (encryption/decryption) can be reduced, otherwise I guess RSA would be just too slow in pratice (now 2048 bits keys are the new norm), or our computers would overheat and melt ;-)

Julien
Josh, 2018-07-16
Glad I could help! Although RSA is starting to go out of fashion these days - ECDH & ECDSA are where PKI seem to be headed.
Ryan, 2018-08-31
You do a fantastic job at explaining complicated topics. I must have read eight of your articles in the past two days. What would you say is the key difference (pun intended) of SSH and SSL? They store the public/private key pairs differently, but I don't see anything major.
Josh, 2018-09-04
Thanks, glad you've enjoyed them - I enjoy writing them. You're right, SSH & SSL solve a lot of the same problems in similar ways; they overlap quite a bit with IPSEC as well, but they're geared toward different enough use cases that they continue to be separate protocols. At the risk of oversimplifying, SSH is a fairly specific protocol designed to encrypt terminal I/O. SSL is a bit more general, designed to encrypt arbitrary higher-level protocol traffic above the network layer, and IPSEC is even MORE general, designed to encrypt nearly everything. They all three still use public key cryptography to encrypt a symmetric cryptography session key and provide message authentication codes.
Eyal Yaron, 2021-06-14
use to connect to snowflake
My Book

I'm the author of the book "Implementing SSL/TLS Using Cryptography and PKI". Like the title says, this is a from-the-ground-up examination of the SSL protocol that provides security, integrity and privacy to most application-level internet protocols, most notably HTTP. I include the source code to a complete working SSL implementation, including the most popular cryptographic algorithms (DES, 3DES, RC4, AES, RSA, DSA, Diffie-Hellman, HMAC, MD5, SHA-1, SHA-256, and ECC), and show how they all fit together to provide transport-layer security.

My Picture

Joshua Davies

Past Posts