【问题标题】:MD5 implementation in C for a XML fileXML文件的C语言MD5实现
【发布时间】:2010-01-28 14:00:33
【问题描述】:

我需要实现 MD5 校验和来验证 XML 文件中的 MD5 校验和,该文件包括所有 XML 标记并且从我们的客户端接收到。接收到的 MD5 校验和的长度是 32 字节的十六进制数字。

在校验和计算之前,我们需要在接收到的XML文件中设置MD5校验和字段为0,并且我们必须独立计算和验证接收到的XML文件中的MD5校验和值。

我们的应用程序是用 C 实现的。请帮助我如何实现它。

谢谢

【问题讨论】:

  • google "MD5 C" 会弹出一堆基于标头的实现。
  • 您的意思是要将整个 XML 文件视为一个大文本文件,对吗?还是必须以某种方式查看 XML 内部?
  • 是的,我想将整个 XML 文件视为一个大文件。客户端 MD5 校验和在该 XML 文件中也可用。我需要在计算之前将该 MD5 校验和替换为 0。
  • 在这种情况下,文件包含 XML 的事实是无关紧要的。 (它可以包含任何字节序列——你要对它做的事情保持不变。)

标签: c xml md5 checksum


【解决方案1】:

这直接取决于用于 XML 解析的库。然而,这很棘手,因为您不能将 MD5 嵌入 XML 文件本身,因为在将校验和嵌入其中之后,除非您仅从特定元素执行校验和。据我了解,您独立收到 MD5 吗?它是从整个文件中计算出来的,还是只从标签/内容中计算出来的?

确切的解决方案取决于所使用的代码。

根据您的评论,您需要执行以下步骤:

  • 加载 xml 文件(甚至可能是纯文本)读取 MD5
  • 用零替换文件中的 MD5,将文件写下来(或更好地写入内存)
  • 对纯文件数据运行MD5,并与之前存储的值进行比较

【讨论】:

  • 是的,我想将整个 XML 文件视为一个大文件。客户端 MD5 校验和在该 XML 文件中也可用。我需要在计算之前将该 MD5 校验和替换为 0。
  • “这很棘手,因为您不能将 MD5 嵌入 XML 文件本身”。在我看来,构建过程好像是“构建文档,校验和字段设置为零;MD5sum 它;用值替换 0”。验证是“找到校验和值并用 0 替换;MD5sum 它;将结果与删除的值进行比较”。
【解决方案2】:

您应该使用 MD5 的公共域实现,而不是自己编写。我听说 Colin Plumb 的版本被广泛使用。

【讨论】:

    【解决方案3】:

    不要重新发明轮子,使用经过验证的现有解决方案:http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html

    顺便说一句,这是我googled "md5 c implementation"时出现的第一个链接。

    【讨论】:

      【解决方案4】:

      这是相当讨厌的。建议的方法似乎暗示您需要将 XML 文档解析为 DOM 树之类的东西,找到 MD5 校验和并将其存储以供将来参考。然后,在重新序列化文档并计算其 MD5 哈希值之前,您将用 0 替换校验和。这一切听起来可行但可能很棘手。我看到的主要困难是您对文档的新序列化可能与原始序列化不同,并且(与 XML 无关)差异(例如在属性值周围使用单引号或双引号、添加换行符甚至不同的编码)导致哈希不同。如果你走这条路,你需要确保你的应用程序和用于创建文档的过程首先做出相同的选择。对于这类问题,规范的 XML 是标准解决方案 (http://www.w3.org/TR/xml-c14n)。

      但是,我会做一些不同的事情。如果运气好的话,应该很容易编写一个正则表达式来定位文件中的 MD5 哈希并将其替换为 0。然后您可以使用它来获取哈希并在重新计算哈希之前在 XML 文件中将其替换为 0。这回避了解析、更改和重新序列化 XML 文档的所有可能问题。为了说明,我将假设哈希 '33d4046bea07e89134aecfcaf7e73015' 存在于 XML 文件中,如下所示:

      <docRoot xmlns='some-irrelevant-uri>
        <myData>Blar blar</myData>
        <myExtraData number='1'/>
        <docHash MD5='33d4046bea07e89134aecfcaf7e73015' />
        <evenMoreOfMyData number='34'/>
      </docRoot>
      

      (我称之为 hash.xml),MD5 应该被 32 个零替换(所以散列是正确的)并使用 perl、md5 和 bash 在 shell 命令行上说明该过程。 (鉴于正则表达式和散列库的存在,希望将其翻译成 C 语言不会太难。)

      分解问题,您首先需要能够找到文件中的哈希:

      perl -p -e'if (m#<docHash.+MD5="([a-fA-F0-9]{32})#) {$_ = "$1\n"} else {$_ = ""}' hash.xml 
      

      (通过查找 docHash 元素的 MD5 属性的开头,允许其他可能的属性,然后抓取接下来的 32 个十六进制字符。如果找到它们,它会将它们插入魔术 $_ 变量中,如果不是将 $_ 设置为空,然后为每一行打印 $_ 的值。这会导致打印字符串“33d4046bea07e89134aecfcaf7e73015”。)

      然后你需要计算文件的哈希值已经被零替换:

      perl -p -e's#(<docHash.+MD5=)"([a-fA-F0-9]{32})#$1"000000000000000000000000000000#' hash.xml | md5
      

      (其中正则表达式几乎相同,但这次十六进制字符被零替换并打印整个文件。然后通过 md5 散列程序将结果管道化来计算其 MD5。把这些放在一起有点 bash 给出:

      if [ `perl -p -e'if (m#<docHash.+MD5="([a-fA-F0-9]{32})#) {$_ = "$1\n"} else {$_ = ""}' hash.xml` = `perl -p -e's#(<docHash.+MD5=)"([a-fA-F0-9]{32})#$1"000000000000000000000000000000#' hash.xml | md5` ] ; then echo OK; else echo ERROR; fi
      

      执行这两个小命令,比较输出并在输出匹配时打印“OK”,如果不匹配则打印“ERROR”。显然这只是一个简单的原型,并且使用了错误的语言,我认为它说明了最直接的解决方案。

      顺便说一句,为什么要将哈希值放在 XML 文档中?据我所见,与在侧通道上传递散列(甚至像在名为 documentname.md5 的第二个文件中那样简单)相比,它没有任何优势,并且使散列验证更加困难。

      【讨论】:

        【解决方案5】:

        查看这些示例,了解如何在 .net 中使用 XMLDSIG 标准

        您或许应该考虑更改保留空格的设置。

        【讨论】:

          猜你喜欢
          • 2014-08-20
          • 1970-01-01
          • 2012-06-07
          • 2011-05-09
          • 2013-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多