0

This is not a 100% c# or ASP.NET question, it's rather a mixture of security and programming. So I apologize ahead. I need to integrate file signing module to my ASP.NET web application. I also need to write a utility application that will verify the signature. I know how to both sign a file and verify it. Here's how I do signing:

       private byte[] SignFile(byte[] fileData){
        X509Certificate2 cert=GetCertificate();
        RSACryptoServiceProvider csp = cert.PrivateKey;

        SHA1Managed sha1 = new SHA1Managed();
        byte[] hash = sha1.ComputeHash(fileData);
        return csp.SignData(hash, CryptoConfig.MapNameToOID("SHA1"));
      }

So far so good. On the other hand, when verifying I will need the public key. So here's my question. Do I need to send the certificate with the signed file so that the other side can take the public key to verify the signature. If so, this brings another question to mind: Can't someone else take the private key from attached certificate to edit the file and sign it again? What is the proper way of doing this?

Mikayil Abdullayev
  • 11,458
  • 22
  • 103
  • 189

1 Answers1

0

To verify a signature that you create using a pub/private key pair, the other party needs your public key only. You should always protect your private key and never let it get out, or a malicious party can pretend to be you.

With X509Certificate2 you can use the GetPublicKeyString method to get the hex string and pass it to them in a text format. You may also simply use the Export and Import methods to exchange only the public key.

PGP works on exactly the same principle, but assumes that the public key is exchanged through a separate trusted channel (such as a physical meeting and exchange of USB stick) so that the recipient knows that the public key is real and not a fake. If you are using certificates from a CA then the CA signing chain will imply the public key trust for you to as good a degree as is practically possible.

Code sample for Export and Import:

var cspSig = (RSACryptoServiceProvider)cert.PrivateKey;
var sig = cspSig.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
var pubKeyBytes = cert.Export(X509ContentType.Cert);
// either send the client the bytes, or the cert file ...
File.WriteAllBytes("MyCert.cer", pubKeyBytes);

and on the client ...

var pubCert = new X509Certificate2();
pubCert.Import(pubKeyBytes);
var cspVer = (RSACryptoServiceProvider)pubCert.PublicKey.Key;
var isValid = cspVer.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), sig);
var hasPrivateKey = pubCert.HasPrivateKey; // will equal false if using .Export(X509ContentType.Cert)
Andy Brown
  • 18,200
  • 3
  • 46
  • 59
  • Ok, so this is the culmination point: In what form is the public key provided? Inside a certificate or as some kind of data? – Mikayil Abdullayev May 05 '14 at 09:21
  • If you use `Export` and `Import` then you are exporting it as the bytes of a certificate file. How you transfer it to the client is up to you. Code sample above. – Andy Brown May 05 '14 at 19:27
  • In this case the Client can able to see private key too.. Even the middle man, var cspVer = (RSACryptoServiceProvider)pubCert.Privatekey; – Champ Sep 18 '17 at 09:02
  • @Vijay I'm almost certain that isn't the case. This answer is years old, but iirc `cert.Export(X509ContentType.Cert)` exports only the public key, not the private key. See also [this answer](https://stackoverflow.com/a/912167/1945631) – Andy Brown Sep 27 '17 at 16:31