C# Validate Signature

2019-04-10 18:28发布

I have the following code to sign my data before sending it (http):

    internal static byte[] Encode(byte[] arMessage, string signerCert, string signerPassword)
            {
                X509Certificate2 cert = new X509Certificate2(signerCert, signerPassword);
                //debug data
                var msg = System.Text.ASCIIEncoding.ASCII.GetString(arMessage);
                //--
                ContentInfo contentInfo = new ContentInfo(arMessage);

                SignedCms signedCms = new SignedCms(contentInfo, true); // <- true detaches the signature
                CmsSigner cmsSigner = new CmsSigner(cert);

                signedCms.ComputeSignature(cmsSigner);
                byte[] signature = signedCms.Encode();

                return signature;
            }

I can see the signature after doing the following:

    string sig = Convert.ToBase64String(bSignature) + MESSAGE_SEPARATOR;
    //this will be included in the message:
    bSignature = System.Text.ASCIIEncoding.ASCII.GetBytes(sig);

    //debug data, see the signature:
    string deb8 = System.Text.ASCIIEncoding.ASCII.GetString(bSignature);
    //--

For example:

MIICvgYJKoZIhvcNAQcCoIICrzCCAqsCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCAbgwggG0MIIBXqADAgECAhAGicJ2MhB7tUZtG3QcdWDwMA0GCSqGSIb3DQEBBAUAMBYxFDASBgNVBAMTC1Jvb3QgQWdlbmN5MB4XDTExMDUwMzEyMTQ0NVoXDTM5MTIzMTIzNTk1OVowDzENMAsGA1UEAxMEVGVzdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuOm4jGHUzLPNww6sx7cZJJxjLIDL/rVVLOtDd1NeA4DZZM1+lKwLpDp3FrV1CA4NP7g3weTg6Y0Jb6X7CSQHnfHRzU8LLrHgp/D9NJ39/RhsKggUteMa1FUUas0fMDMELtTO07ejNfYAhDYQiXmeg+pIMpUfeUhMicyV2xrPzG8CAwEAAaNLMEkwRwYDVR0BBEAwPoAQEuQJLQYdHU8AjWEh3BZkY6EYMBYxFDASBgNVBAMTC1Jvb3QgQWdlbmN5ghAGN2wAqgBkihHPuNSqXDX0MA0GCSqGSIb3DQEBBAUAA0EAVIjI0My490lY6vKrcgorZZ8MBo3MSk9HuDRBE0SRwSQjnvPsAD0ol1ZjvzjFKA/0Vgvp1lyYquCTSL8R/uWf+TGBzzCBzAIBATAqMBYxFDASBgNVBAMTC1Jvb3QgQWdlbmN5AhAGicJ2MhB7tUZtG3QcdWDwMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYCuXG2CJ0G6UaO1AVMpo5ul3JkJ9EvJbdwb6sXOqOonq5qKbaGJsx0sgwoBfg3lLMP3UI9JVi4dTGG4KTzA1k/0Qt0owmEPKrDh3zVZr2hK/iHsW75sGjSgYT4hxbn6ziQ2IFoN2qCbxdXrMZ+TD0pf7o/ABdorjlvQ5USwlPKjZQ==

This is what I have in the received message. So the question is: how to validate the signature of the received message on the recipient (has the .cer file provided)? Thanks in advance

Edit 1:

I tried to follow the Daniel Hilgarth's logic but it didn't worked. A few times I met the "ASN Bad tag value" exception. To make it easier, I hardcoded the message being used to generate the signature So, on the receiver I have 2 things: the original message and the signature generated for it:

    //Signature from the message  (string in ASCII)
    var signatureKey = GetSignatureFromSignatureMessage(signatureMessage, boundary);
    //Original sent message (the arMessage itself used in Encode method above, converted to string from byte) 
    var messageOriginal =
        "Content-Type: application/EDIFACT\r\nContent-Transfer-Encoding: binary\r\n\r\nSome short text.\r\nVery short.";

I need to check if the signature corresponds this message. So I am trying to do something like this:

//contentInfo from the original message.
ContentInfo contentInfo = new ContentInfo(System.Text.ASCIIEncoding.ASCII.GetBytes(messageOriginal));

//SingedCms from the contentInfo above
SignedCms signedCms = new SignedCms(contentInfo, true);

//Here, I believe, I am attaching the signature I have to the Cms    
 signedCms.Decode(System.Text.ASCIIEncoding.ASCII.GetBytes(signatureKey));

//checking?
signedCms.CheckSignature(true);

And I get exceptions on decode part.

Any advices?

Edit 2: Solution: The direction given by Daniel Hilgarth is right. My problem was that the sender encoded the key few times: Base64 byte array -> Base64String -> ASCII byte array -> ASCII string -> Send_message The receiver was receiving the data in ASCII already, doing: ASCII String -> Byte array. I had to convert everything back to base64 byte array to make it work.

    //Signature from the message (ASCII String)
    var signatureKey = GetSignatureFromSignatureMessage(signatureMessage, boundary);

    //Original Byte Array (Base64)
    var sigKeyBase = Convert.FromBase64String(signatureKey);

   //Original sent message
    var messageOriginal =
        "Content-Type: application/EDIFACT\r\nContent-Transfer-Encoding: binary\r\n\r\nSome short text.\r\nVery short.";

    var messageOriginalByteASCII = System.Text.ASCIIEncoding.ASCII.GetBytes(messageOriginal);


    ContentInfo contentInfo = new ContentInfo(messageOriginalByteASCII);
    SignedCms signedCms = new SignedCms(contentInfo, true);
    signedCms.Decode(sigKeyBase);

    signedCms.CheckSignature(true);

In this case it passes Check. P.S. Too bad ChekSignature doesn't return true or false. I'd be more comfortable imho. :(

1条回答
爷的心禁止访问
2楼-- · 2019-04-10 19:01

Hm... maybe using SignedCms.CheckSignature?! Use it in conjunction with SignedCms.Decode. Basically, just use the reverse way you use to sign the document. An example with detached signature is available from the MSDN page:

// Create a ContentInfo object from the inner content obtained 
// independently from encodedMessage.
ContentInfo contentInfo = new ContentInfo(innerContent);

// Create a new, detached SignedCms message.
SignedCms signedCms = new SignedCms(contentInfo, true);

// encodedMessage is the encoded message received from 
// the sender.
signedCms.Decode(encodedMessage);

// Verify the signature without validating the 
// certificate.
signedCms.CheckSignature(true);
查看更多
登录 后发表回答