Skip to content
ecdsa.com

Key fingerprint · Ruby

How to compute a public key fingerprint in Ruby

To compute a public key fingerprint in Ruby, hash public_to_der with OpenSSL::Digest::SHA256 — the key's DER-encoded SubjectPublicKeyInfo, which Ruby's openssl library returns directly. The digest matches OpenSSL's DER pipe and every other recipe on this site, for bare keys and for the key inside a certificate.

Tested with openssl (Ruby gem) 4.0.2 (Ruby 4.0.7, OpenSSL 3.5.7) and OpenSSL 3.5.7 (openssl dgst cross-check).

fingerprint.rb — SHA-256 over SPKI DER, as hex and as a base64 pin
require "openssl"
public_key = OpenSSL::PKey.read(File.read("pub.pem")) # parsing first: a non-key fails here
digest = OpenSSL::Digest::SHA256.digest(public_key.public_to_der) # SPKI DER, 91 bytes for P-256
puts digest.unpack1("H*").scan(/../).join(":") # the layout of openssl dgst -c
puts [digest].pack("m0") # pin-sha256 (RFC 7469)
the key inside a certificate versus the certificate itself
# The key inside a certificate: hash its SPKI, not the certificate
cert = OpenSSL::X509::Certificate.new(File.read("cert.pem"))
puts "certificate key: #{OpenSSL::Digest::SHA256.hexdigest(cert.public_key.public_to_der)}"
puts "certificate itself: #{OpenSSL::Digest::SHA256.hexdigest(cert.to_der)}"

How it works

  1. OpenSSL::PKey.read parses the key first, so a damaged file raises Could not parse PKey instead of yielding a fingerprint of noise.
  2. public_to_der re-encodes the public half as canonical SPKI DER — the same 91 bytes for a P-256 key whether it came from a PEM file, a private key or a certificate.
  3. unpack1("H*") with scan(/../).join(":") gives the openssl dgst -c layout; pack("m0") the strict base64 pin-sha256 form.
  4. For a certificate, cert.public_key.public_to_der hashes the key; cert.to_der would hash the whole certificate. The run prints both and compares the key digest with OpenSSL.

Gotchas

  • Called on a private key, to_der returns the private key encoding, not SPKI — always use public_to_der for fingerprints, which works on private and public key objects alike.
  • The certificate fingerprint (54:7a:73:… for the example) changes on every renewal; the key fingerprint (3d:bb:28:…) stays the same as long as the key does — pin that one.
  • OpenSSL::Digest::SHA256.hexdigest(File.read("pub.pem")) hashes PEM text and matches no other tool.
  • OpenSSH fingerprints (SHA256:… from ssh-keygen -lf) hash the SSH encoding of the key and never equal the SPKI value.

Related recipes