Question

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.

Was it helpful?

Solution

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 .

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top