104

When I import my OpenSSH public key into AWS EC2's keyring the fingerprint that AWS shows doesn't match what I see from:

ssh-keygen -l -f my_key

It is a different length and has different bytes.

Why? I'm sure I uploaded the correct key.

Craig Ringer
  • 10,553
  • 9
  • 38
  • 59

8 Answers8

156

AWS EC2 shows the SSH2 fingerprint, not the OpenSSH fingerprint everyone expects. It doesn't say this in the UI.

It also shows two completely different kinds of fingerprints depending on whether the key was generated on AWS and downloaded, or whether you uploaded your own public key.

Fingerprints generated with

ssh-keygen -l -f id_rsa

will not match what EC2 shows. You can either use the AWS API tools to generate a fingerprint with the ec2-fingerprint-key command, or use OpenSSL to do it.

Note that if you originally generated a key on AWS, but then uploaded it again (say, to another region) then you'll get a different fingerprint because it'll take the SSH2 RSA fingerprint, rather than the sha1 it shows for keys you generated on AWS.

Fun, hey? This screenshot has two copies of the same key in it with different fingerprints

In the above, test-generated was generated using AWS EC2. test-generated-reuploaded is the public key from the private key AWS generated, extracted with ssh-keygen -y and uploaded again. The third key, test-uploaded, is a locally generated key ... but the local ssh-keygen -l fingerprint is b2:2c:86:d6:1e:58:c0:b0:15:97:ab:9b:93:e7:4e:ea.

$ ssh-keygen -l -f theprivatekey
2048 b2:2c:86:d6:1e:58:c0:b0:15:97:ab:9b:93:e7:4e:ea
$ openssl pkey -in theprivatekey -pubout -outform DER | openssl md5 -c
Enter pass phrase for id_landp:
(stdin)= 91:bc:58:1f:ea:5d:51:2d:83:d3:6b:d7:6d:63:06:d2

Keys uploaded to AWS

When you upload a key to AWS, you upload the public key only, and AWS shows the MD5 hash of the public key.

You can use OpenSSL, as demonstrated by Daniel on the AWS forums, to generate the fingerprint in the form used by AWS to show fingerprints for uploaded public keys (SSH2 MD5), like:

7a:58:3a:a3:df:ba:a3:09:be:b5:b4:0b:f5:5b:09:a0

If you have the private key, you can generate the fingerprint by extracting the public part from the private key and hashing it using:

openssl pkey -in id_rsa -pubout -outform DER | openssl md5 -c

If you only have the public key, and it is in OpenSSH format, you need to first convert it to PEM and then DER and then hash, using:

ssh-keygen -f id_rsa.pub -e -m PKCS8 | openssl pkey -pubin -outform DER | openssl md5 -c

Keys generated on AWS

When you generate a keypair on AWS, AWS shows the SHA1 hash of the private key, which is longer, like:

ea:47:42:52:2c:25:43:76:65:f4:67:76:b9:70:b4:64:12:00:e4:5a

In this case you need to use the following command, also shown by Daniel on the AWS forums, to generate a sha1 hash based on the private key:

openssl pkcs8 -in aws_private.pem -nocrypt -topk8 -outform DER | openssl sha1 -c

on the downloaded AWS-generated private key/certificate file. It'll work on keys you converted to OpenSSH format too. This does, however, require that you have the private key, since the hash is of the private key. You cannot generate the hash locally if all you have is the public key.

References

See:

Old Pro
  • 1,335
  • 10
  • 20
Craig Ringer
  • 10,553
  • 9
  • 38
  • 59
  • 7
    Sad the missing clarity from AWS about it, they are opening a potential security breach making it harder to verify keys – Jaime Hablutzel Oct 18 '14 at 04:55
  • 1
    Great answer! On the initial `ssh` command, with more recent versions you need a -E option to specify md5 format: `ssh-keygen -E md5 -l -f id_rsa`. – RichVel Apr 07 '17 at 05:50
  • Absolutely brilliant answer, covering all the quirks and all the conversions you might need. For me, `openssl pkcs8 -in aws_private.pem -nocrypt -topk8 -outform DER | openssl sha1 -c` what was I was looking for to match a key I had downloaded with what was shown on the EC2 console. – JHH Sep 16 '21 at 06:51
  • typical AWS attitude that do not care about developers. – mon Feb 16 '22 at 01:46
23

If you only have public keys, you can generate the AWS fingerprint as follows:

ssh-keygen -e -f id_rsa.pub -m pkcs8 | openssl pkey -pubin -outform der | openssl md5 -c
techraf
  • 4,163
  • 8
  • 27
  • 44
J. Doe
  • 381
  • 2
  • 2
4

There's a resource on AWS docs http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#verify-key-pair-fingerprints

If you created your key pair using AWS, you can use the OpenSSL tools to generate a fingerprint from the private key file:

Copy

$ openssl pkcs8 -in path_to_private_key -inform PEM -outform DER -topk8 -nocrypt | openssl sha1 -c

If you created your key pair using a third-party tool and uploaded the public key to AWS, you can use the OpenSSL tools to generate a fingerprint from the private key file on your local machine:

Copy

$ openssl rsa -in path_to_private_key -pubout -outform DER | openssl md5 -c

The output should match the fingerprint that's displayed in the console.

goutham
  • 149
  • 1
3

This is what I use:

openssl rsa -RSAPublicKey_in -in <(ssh-keygen -f ~/.ssh/id_rsa.pub -e -m PEM) -inform PEM -outform DER 2>/dev/null | openssl md5 -c | awk '{print $2}'

This generates the fingerprint from the public key, similar to some of the above.

Max Murphy
  • 151
  • 3
1

Just in case this could be useful: https://ssh-vault.com/post/fingerprint/

for example:

$ ssh-vault -u bob -f

Will print the fingerprint for user bob matching the format AWS is using.

nbari
  • 548
  • 1
  • 8
  • 25
1

For those of us using Python

from Crypto.PublicKey import RSA
import hashlib
import base64

#Load your key from disk, or a string, or generate.
my_key = RSA.importKey(open(my_rsa_private_key, 'r').read())

# Normal md5 fingerprint
fp_plain = hashlib.md5(base64.b64decode(my_key.exportKey('OpenSSH').strip().split()[1].encode('ascii'))).hexdigest()
print ':'.join(a+b for a,b in zip(fp_plain[::2], fp_plain[1::2]))

#AWS' EC2 fingerprint
public_only_key = RSA.importKey(my_key.exportKey('OpenSSH'))
fp_plain = hashlib.md5(public_only_key.exportKey('DER')).hexdigest()
print ':'.join(a+b for a,b in zip(fp_plain[::2], fp_plain[1::2]))
Andy
  • 130
  • 4
  • Unfortunately this failed for me on macOS 10.11 using latest Homebrew Python 2.7.13, with this error: `ValueError: PEM encryption format not supported.` – RichVel Apr 07 '17 at 05:45
  • @RichVel, I cannot reproduce the error. I just tested is on macOS 10.12 using homebrew python 2.7.13 in a virtualenv, and it worked just fine. If I had to guess, maybe some of the C requirements for pycrypto were not met for you. Maybe [this](http://stackoverflow.com/questions/19617686/trying-to-install-pycrypto-on-mac-osx-mavericks) might help? – Andy Apr 11 '17 at 21:14
1
#!/bin/bash
key_file=$1
if [[ -n $key_pub_file ]]; then
    ssh-keygen -e -f $key_pub_file -m pkcs8 | openssl pkey -pubin -outform der | openssl md5 -c
else
    echo "pass the pub file as argument"
fi

Here is a script that I use, add the script path to env. Thanks to J.Doe for the answer

0

Java (using BouncyCastle). If the AWS console displays shorter keys, try with MD5. (SHA1: 20 bytes, MD5: 16 bytes).

  /**
   * @return the SHA1 digest of the DER encoded RSA private key, e.g. 16:61:7d:1c:e7:d1:3b:93:b6:81:bf:64:7a:a0:38:fa:b6:6c:9e:e4
   */
  private String getAwsFingerprint(File rsaPrivateKeyFileFromAws) throws Exception {
    try(FileReader reader = new FileReader(rsaPrivateKeyFileFromAws)) {
      java.security.KeyPair keyPair = new JcaPEMKeyConverter().getKeyPair((PEMKeyPair) new PEMParser(reader).readObject());
      String hex = Hex.toHexString(MessageDigest.getInstance("SHA1").digest(keyPair.getPrivate().getEncoded()));
      StringBuilder sb = new StringBuilder();
      for(int i = 0; i < hex.length();) {
        sb.append(hex.charAt(i++));
        sb.append(hex.charAt(i++));
        sb.append(i % 2 == 0 && i != hex.length() ? ":" : "");
      }
      return sb.toString();
    }
  }
Reto Höhener
  • 411
  • 3
  • 7
  • 15