Mike Dinescu
Mike Dinescu

Reputation: 55720

RSA_sign and RSACryptoProvider.VerifySignature

I'm trying to get up to speed on how to get some code that uses OpenSSL for cryptography, to play nice with another program that I'm writing in C#, using the Microsoft cryptography providers available in .NET.

More to the point, I'm trying to have the C# program verify an RSA message signature generated by the OpenSSL code. The code that generates the signature looks something like this:

// Code in C, using the OpenSSL RSA implementation

char msgToSign[] = "Hello World";     // the message to be signed
char signature[RSA_size(rsa)];        // buffer that will hold signature
int slen = 0;                         // will contain signature size

// rsa is an OpenSSL RSA context, that's loaded with the public/private key pair

memset(signature, 0, sizeof(signature));

RSA_sign(NID_sha1
      , (unsigned char*)msgToSign
      , strlen(msgToSign)
      , signature
      , &slen
      , rsa);

// now signature contains the message signature
//  and can be verified using the RSA_verify counterpart
// .. I would like to verify the signature in C#

In C#, I would do the following:

I've got the first two parts working (I've verified that the public key is loading properly because I managed to send an RSA encrypted text from the C# code to the OpenSSL code in C and successfully have it decrypted)

In order to verify the signature in C#, I've tried using the: VerifySignature method of the RSACryptoServiceProvider but that didn't work. And digging around the internet I was only able to find some vague information pointing out that .NET uses a different method for generating the signature than OpenSSL does. So, does anybody know how to accomplish this?

EDIT

Since there was a request, here's the C# side of things..

byte[] receivedSignature;
// ....
// receivedSignature is set to the byte array generated by the OpenSSL side
//   I've verified this much is working correctly

// I use my utility to parse a PEM file and extract the other side's public key
//   also, verified to be working correctly - the public key is good.
RSACryptoServiceProvider rsa = MyPEMLoader.LoadFromFile("publicKey.pem");

string msgToVerify = "Hello World";
byte[] msgBytes = Encoding.ASCII.GetBytes(msg);  // other side uses ASCII, so do the same
bool verified = rsa.VerifyHash(msgBytes, "SHA1", receivedSignature);

// verfied is false.. verfification failed!

Upvotes: 2

Views: 5059

Answers (2)

Andrus
Andrus

Reputation: 27931

You should remove your pem utility, this is not required and use

 var cert = new X509Certificate2(HttpContext.Current.Request.MapPath("~/App_Data/PublicKey.pem"), "");
var rsaCryptoIPT = (RSACryptoServiceProvider)cert.PublicKey.Key;
var sha1 = new SHA1CryptoServiceProvider();
if (!rsaCryptoIPT.VerifyData(data, sha1, signature))
                throw new InvalidOperationException("Invalid signature from bank ");

If this does not help can you post pem file reader code.

Upvotes: 0

Henk Holterman
Henk Holterman

Reputation: 273244

It might help if you showed your C# code. I think it should be something like:

    string msg = ...;
    byte[] localData = Encoding.UTF8.GetBytes(msg);
    bool ok = rsa.VerifyHash(localData, "SHA1", receivedhash);

And of course I'm just guessing the UTF-8 part. Might be ASCII as well.

Edit: Here is the MSDN page. The example seems to do it different, localData is hashed first.

hashedData = hash.ComputeHash(signedData);
return rsaCSP.VerifyHash(hashedData, CryptoConfig.MapNameToOID("SHA1"), signature);

Upvotes: 1

Related Questions