title: C# Generating Thumbprint of CSR or Key
body: <p>I am writing a simple application to generate the thumbprint of a certificate, CSR, or key and print it to a txtBox to compare them to see if they are a match. I was able to obtain the thumbprint for the certificate using the existing <a href="https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.thumbprint%28v=vs.110%29.aspx" rel="nofollow noreferrer">Microsoft documentation</a>. But I havent been able to do this with bouncy castle for the CSR or private key. I found <a href="https://stackoverflow.com/questions/44440974/bouncy-castle-decode-csr-c-sharp">this thread</a> which extracts the subject info from a CSR. I also found some documentation <a href="https://www.programcreek.com/java-api-examples/index.php?source_dir=hudson_plugins-master/ec2/src/main/java/hudson/plugins/ec2/EC2PrivateKey.java" rel="nofollow noreferrer">here</a> which suggests using this Java code to do it for the private key. But im not exactly sure whats happening here and dont know how to convert it to C#.</p>
  
  <pre><code>public String getFingerprint() throws IOException { 
    Security.addProvider(new 
                        org.bouncycastle.jce.provider.BouncyCastleProvider()); 
    Reader r = new BufferedReader(new StringReader(privateKey.toString())); 
    PEMReader pem = new PEMReader(r); 
    KeyPair pair = (KeyPair) pem.readObject(); 
    if(pair==null)  return null; 
    PrivateKey key = pair.getPrivate(); 
    return digest(key); 
  } 
  </code></pre>
  
  <p>Currently, I have the following code which appears to give me the thumbprint, but it doesn't match the thumbprint created by OpenSSL. I'm sure this is due to me using the wrong input to generate the hex string. But im not sure what input I should be giving it.</p>
  
  <pre><code>public static string GetCsrMd5(string input)
      {
          using (System.Security.Cryptography.MD5 md5 = 
          System.Security.Cryptography.MD5.Create())
          {
              string header = "-----BEGIN NEW CERTIFICATE REQUEST-----";
              string footer = "-----END NEW CERTIFICATE REQUEST-----";
              byte[] csr = Convert.FromBase64String(input.Replace(header, 
                                                 "").Replace(footer, ""));
              byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
              byte[] hashBytes = md5.ComputeHash(inputBytes);
              StringBuilder sb = new StringBuilder();
              for (int i = 0; i &lt; hashBytes.Length; i++)
              {
                  sb.Append(hashBytes[i].ToString("x2"));
              }
              return sb.ToString();
          }
       }
  </code></pre>
  
  <p>To generate the fingerprint, what value needs to be assigned to <code>hashBytes</code>? Or is there an existing method for this via bouncy castle?</p>
  
  <p>UPDATE:</p>
  
  <p>Based on OpenSSL, I either need to be passing the modulus or the public key from the CSR/KEY to <code>sig</code> to be hashed. Here are the OpenSSL commands I am using to compare fingerprints:</p>
  
  <pre><code>openssl req -noout -modulus -in domain.csr | openssl md5
  openssl rsa -noout -modulus -in domain.key | openssl md5
  openssl x509 -noout -modulus -in domain.crt | openssl md5
  </code></pre>
  
  <p>I have fixed some errors in the original code, but I am getting an error when computing the hash of <code>sig</code>.</p>
  
  <pre><code>Error   CS1503  Argument 1: cannot convert from 
  'Org.BouncyCastle.Crypto.AsymmetricKeyParameter' to 'System.IO.Stream'
  </code></pre>
  
  <p>Oddly enough I can run the code with the error but generating the fingerprint only returns <code>0??0??</code>. I have tried making the <code>sig</code> variable a byte[], string, stream, but each error is pretty much the same 'cannot implicitly convert.' But I get the same unreadable characters returned. Im sure I need to import the public key into somesort of RSA instance then export the bytes, but the lack of documentation working with BouncyCastle in C# has made this difficult. I will update again once I figure that out.</p>
  
  <p>The updated code:</p>
  
  <pre><code>        public static string GetCsr(string input)
          {
              string header = "-----BEGIN NEW CERTIFICATE REQUEST-----";
              string footer = "-----END NEW CERTIFICATE REQUEST-----";
              // Remove header and footer
              byte[] csr = Convert.FromBase64String(input.Replace(header, 
                                                 "").Replace(footer, ""));
              // Load CSR body into a PKCS10 instance
              Pkcs10CertificationRequest csrBytes = new 
                                           Pkcs10CertificationRequest(csr);
              // Get Public Key from existing instance
              byte[] sig = csrBytes.GetPublicKey();
              System.Security.Cryptography.HashAlgorithm create = 
                                 System.Security.Cryptography.MD5.Create();
              // Compute MD5 hash and convert to hex string
              byte[] test = create.ComputeHash(sig);
              StringBuilder sb = new StringBuilder();
              for (int i = 0; i &lt; test.Length; i++)
              {
                  sb.Append(test[i].ToString("x2"));
              }
              string fingerprint = sb.ToString();
              // Return hex string
              return fingerprint;
          }
  </code></pre>