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 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
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 :email@example.com
stdoutand 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-----
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
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
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,
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
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
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,
are included in the public key (certificate) file and
are included in the private key file: therefore, to determine if the key files are related,
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
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
q) which are not secret, and a pair of
y related such that
y = gx % p
(q is used during the signature generation and verification process and is related to
p. Again, for full details, refer to my book).
x is the private
y is the public key.
If you want to create a DSA keypair with openssl, you must first generate the DSA
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-----
This is a direct ASN.1 encoding of
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
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 :firstname.lastname@example.org -----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-----
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
Likewise, if you ask for the modulus of the private key file, you'll see the same
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
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
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
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
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-----
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
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
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-----
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-----
-----END PUBLIC KEY-----
You can do this with RSA and DSA keys as well, actually: you can request
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"
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.
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
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
-y to see the public key that corresponds with a private key regardless
of the algorithm, as I'll demonstrate below.
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
$ 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
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
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 (
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
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.
While SSL requires that DSA certificates (and, by extension, DSA public keys) be created in two
steps — DSA parameter generation followed by key generation —
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]-----+
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==
This is all identically true of ECDSA; I won't repeat it here.
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
ssh-ed25519, a specific EdDSA curve.