Skip to content
ecdsa.com

Key fingerprint · .NET

How to compute a public key fingerprint in C# (.NET)

To compute a public key fingerprint in C#, hash the key's SubjectPublicKeyInfo with SHA256.HashData — ExportSubjectPublicKeyInfo returns exactly the canonical DER that OpenSSL, Java and Go hash for the same key. The recipe prints the colon-separated hex and the base64 pin, and shows why a certificate's key fingerprint is not the certificate's own hash.

Tested with .NET 10.0.13 (SDK 10.0.402) (Linux, OpenSSL 3.0.13 backend) and OpenSSL 3.0.13 (openssl dgst cross-check).

fingerprint.cs — SHA-256 over SPKI DER, as hex and as a base64 pin
using System.Security.Cryptography;
using var key = ECDsa.Create();
key.ImportFromPem(File.ReadAllText("pub.pem")); // parsing first: a non-key fails here
byte[] spki = key.ExportSubjectPublicKeyInfo(); // canonical SPKI DER
byte[] digest = SHA256.HashData(spki);
Console.WriteLine(string.Join(":", digest.Select(b => b.ToString("x2")))); // OpenSSL's dgst -c layout
Console.WriteLine(Convert.ToBase64String(digest)); // pin-sha256 (RFC 7469)
the key inside a certificate versus the certificate itself
using System.Security.Cryptography.X509Certificates;
// The key inside a certificate — not cert.GetCertHash(), which hashes the whole certificate
using X509Certificate2 cert = X509CertificateLoader.LoadCertificateFromFile("cert.pem");
byte[] keyDigest = SHA256.HashData(cert.PublicKey.ExportSubjectPublicKeyInfo());
Console.WriteLine($"certificate key: {Convert.ToHexStringLower(keyDigest)}");
Console.WriteLine($"certificate itself: {cert.GetCertHashString(HashAlgorithmName.SHA256)}");

How it works

  1. ImportFromPem parses the key first, so a damaged file or a certificate passed by mistake throws instead of yielding a fingerprint of the wrong bytes.
  2. ExportSubjectPublicKeyInfo() re-encodes the key as SPKI DER — the same 91 bytes for a P-256 key whether it came from PEM, a certificate or ECDsa.Create.
  3. SHA256.HashData is the one-shot hash API (.NET 5+); the hex with colons matches openssl dgst -sha256 -c, the base64 form is the pin-sha256 used by HTTP public key pinning.
  4. For a certificate, cert.PublicKey.ExportSubjectPublicKeyInfo() gives the key's SPKI without choosing between ECDSA and RSA accessors.

Gotchas

  • cert.GetCertHash() and cert.Thumbprint hash the whole certificate — and Thumbprint uses SHA-1. Neither equals the key fingerprint, and both change when the certificate is renewed with the same key.
  • Hashing File.ReadAllBytes("pub.pem") hashes PEM text, including line endings. Only the DER is canonical across tools.
  • Convert.ToHexString returns uppercase and Convert.ToHexStringLower (.NET 9+) lowercase. Normalize case before comparing fingerprints from different tools.
  • OpenSSH fingerprints (SHA256:…) hash the SSH encoding of the key and never match the SPKI fingerprint of the same key.

Related recipes