验证数字签名电子邮件附件“哈希值不正确”

时间:2013-07-23 15:38:27

标签: c# email digital-signature exchangewebservices

我正在尝试验证经过数字签名的电子邮件的签名。它知道签名是正确的,因为outlook验证它。我正在使用SignedCms来执行验证

我有以下消息:

Content-Type: multipart/signed; protocol="application/pkcs7-signature";
    micalg=sha1; boundary="boundary1"

--boundary1
Content-Type: multipart/mixed;
    boundary="boundary2"

--boundary2
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

some text in the body
of the message



--boundary2
Content-Type: application/something;
    name="somefile.txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
    filename="somefile.txt"

FkrMjIwOjE1OCdRVFkrMjIwOjE3NidRVFkrMjIwOjE5MydRVFkrMjIwOjIwNydR
VFkrMjIwOjIyMidRVFkrMjIwOjIzNCdRVFkrMjIwOjI0NSdRVFkrMjIwOjI1OCdRVFkrMjIwOjI2
NidRVFkrMjIwOjI3NydRVFkrMjIwOjI4NSdRVFkrMjIwOjI5MSdRVFkrMjIwOjI5OCdRVFkrMjIw
OjMwMidRVFkrMjIwOjMwNidRVFkrMjIwO
--boundary2--

--boundary1
Content-Type: application/pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"

MIIIEAYJKoZIhvcNAQcCoIIIATCCB/0CAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
DQEHAaCCBW4wggVqMIIEUqADAgECAg4YHgABAAIO2xMJhvDULzANBgkqhkiG9w0B
AQUFADB8MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i


--boundary1--

我在验证签名方面遇到了很大麻烦。

这是我尝试这样做的方式: EmailMessage message = results.ElementAt(13)as EmailMessage;             message.Load();

        var attachments = message.Attachments;
        foreach (var attachment in attachments)
        {
            var fAttachment = attachment as FileAttachment;
            fAttachment.Load();
            string fullMailData = Encoding.UTF8.GetString(fAttachment.Content);
            FileToolbox.WriteStringToFile(@"C:\BeforeDecoding.txt", fullMailData);
            var lines = fullMailData.Split('\n');
            string signature = "";
            string dataPlain = "";
            //These line numbers do not correspond to the example, 
            //because it is altered to hide the real email
            for (int i = 12 - 1; i <= 13 - 1; i++)
            {
                dataPlain += lines[i];
            }
            //These line numbers do not correspond to the example
            //because it is altered to hide the real email
            for (int i = 56 - 1; i <= 99 - 1; i++)
                {
                    signature += lines[i];
                }

            var signedCms = new SignedCms(new ContentInfo(Encoding.ASCII.GetBytes(dataPlain)));
            signedCms.Decode(base64_decode(signature));
            signedCms.CheckHash();
            signedCms.CheckSignature(true);

所以在上面的例子中我只使用带有text / plain的body来检查签名。我还尝试了以下部分:

  1. 从--boundary1到--boundary1的所有内容再次出现。
  2. 只有base64加密的正文部分(然后是base64解码的)
  3. 两个团体的合并
  4. 我试图保留\ r和\ n值
  5. 我试图仅保留\ r \ n值
  6. 每个人都返回无效的哈希值。

    我做错了什么?我应该将哪部分消息传递给新的SignedCms()?

    对解决方案的额外评论 由于来自Web方法的PKCS#7 / CMS消息始终是分离的,因此根据此somewhat acceptable source

    ,应使用detached = true实例化signedcms。
    public SignedCms(
        ContentInfo contentInfo,
        bool detached
    )
    

    对于我的MWE,我将完整的文件内容保存到文件中,然后手动删除了一些行。我没有把字符串分开(但......)。所以我的MWE就这样结束了:

        var fullMessageBytes = File.ReadAllBytes(@"C:\fAttachment_content.txt");
        var isoEncoding = Encoding.GetEncoding("iso-8859-1");
        var fullMessageString = isoEncoding.GetString(fullMessageBytes);
    
        var messageBytes = File.ReadAllBytes(@"C:\message_body.txt");
        var messageBytesString = isoEncoding.GetString(messageBytes);
    
        var signatureStringReadIn = File.ReadAllText(@"C:\certToReadIn.txt");
        var signatureStringReadInBytes = Convert.FromBase64String(signatureStringReadIn);
    
        var signedCms = new SignedCms(new ContentInfo(messageBytes), true);
        signedCms.Decode(signatureStringReadInBytes);
        signedCms.CheckSignature(false);
    

2 个答案:

答案 0 :(得分:2)

所有内容但是不要忘记前面的--boundary1之后的crlf和尾随的-boundary1之后的crlf分别是边界,因此,不得进行散列。

查看规范RFC 5751第3.4.3.3节的示例。 示例多部分/签名消息。

如果我是你,我会尝试将内容从字节转换为字符串并返回字节。相反,我会在字节数组中工作。您的转换始终存在更改内容的风险。

答案 1 :(得分:0)

@mkl - 不幸的是,我还不能添加评论,但我很好奇在RFC 5751中它表示在领先边界之后和第一次重复出现之前的\ r \ n是其中的一部分边界。它有效,但只是想知道它是如何被人知道的。