Earlier our Application-A was in C++ and a message was signed before sending it to Application-B using crypto API functions in C++ , exactly similar to the example described in http://msdn.microsoft.com/en-us/library/windows/desktop/aa382372%28v=vs.85%29.aspx.
This message was again verified by Application-B using Crypto API functions in C++ (the above example again talks about how to verify an already signed message).
Now we are in the process of converting/migrating the old C++ Application-A to C#. I already found a way to sign the message using P-Invoke in C# and when the signed message was verified by Application-B (using C++ CryptVerifySignatureMessage) everything is working fine. Example is available in - http://blogs.msdn.com/b/alejacma/archive/2008/02/21/how-to-sign-a-message-and-verify-a-message-signature-c.aspx .
As @CodeInChaos has mentioned in his comments i want the leave the interop work to the framework (without using P-Invoke or other 3rd party implementation like BountyCastle)
So would like to know whether .net offers any API to sign a message (as a learning perspective too) , if so how can i achieve it.
NOTE:
I already tried crypto wrapper API RSACryptoServiceProvider offered by .Net.
private byte[] SignData(byte[] data, string certThumbPrint)
{
X509Certificate2 cert = GetCertificate(); // finds the certificate with thumbprint
RSACryptoServiceProvider rsaCryptoServiceProvider = (RSACryptoServiceProvider)cert.PrivateKey;
return rsaCryptoServiceProvider.SignData(data, new SHA1CryptoServiceProvider());
}
But found a major difference with the return value (byte array) of CryptSignMessage from C++ and RSACryptoServiceProvider.SignData() method from C#.
• CryptSignMessage: The CryptSignMessage function creates a hash of the specified content, signs the hash, and then encodes both the original message content and the signed hash.
• RSA.SignData: Computes the hash value of the specified byte array using the specified hash algorithm, and signs the resulting hash value.
Because of this difference , the Application-B when it verifies the message it throws error saying 'invalid signing' .
So i cant use this RSACryptoServiceProvider type offered by .net. Is there any other way to achieve the same using any .NET API's ? (when using .net API the output byte array should be similar to that of output when using PInvoke example as mentioned above) so that Application-B can work without any issues.
Any help is appreciated.
After some long research i found a way to do it . If someone else is looking for how to sign a message using PKCS7 format using a certificate in C# then here it is,
public byte[] SignMsg(
Byte[] msg,
X509Certificate2 signerCert)
{
// Place message in a ContentInfo object.
// This is required to build a SignedCms object.
ContentInfo contentInfo = new ContentInfo(msg);
// Instantiate SignedCms object with the ContentInfo above.
// Has default SubjectIdentifierType IssuerAndSerialNumber.
// Has default Detached property value false, so message is
// included in the encoded SignedCms.
SignedCms signedCms = new SignedCms(contentInfo);
// Formulate a CmsSigner object, which has all the needed
// characteristics of the signer.
CmsSigner cmsSigner = new CmsSigner(signerCert);
// Sign the PKCS #7 message.
Console.Write("Computing signature with signer subject " +
"name {0} ... ", signerCert.SubjectName.Name);
signedCms.ComputeSignature(cmsSigner);
Console.WriteLine("Done.");
// Encode the PKCS #7 message.
return signedCms.Encode();
}
Found the information from the link http://msdn.microsoft.com/en-us/library/ms180961%28v=vs.85%29.aspx .