### 启用 XML 安全性(2)

<Expiration>04/02</Expiration>
</CreditCard>
</PaymentInfo>
可能还有必要加密文档中的所有信息，清单 4 演示了这点。
清单 4. 隐藏了全部内容的加密文档
<?xml version='1.0'?>
<EncryptedData xmlns='http://www.w3.org/2001/04/xmlenc#'
Type='http://www.isi.edu/in-notes/iana/assignments/media-types/text/xml'>
<CipherData><CipherValue>A23B45C56</CipherValue></CipherData>
</EncryptedData>
CipherData 可以封装，也可以引用原始加密数据。在第一种情况下，CipherValue 元素的内容显示原始数据，而在第二种情况，使用 CipherReference 元素，这包括了一个指向加密数据位置的 URI。
规范的 XML
对应用了密码散列算法的消息进行最轻微的更改也会产生不同的值。这为消息完整性方面提供了信任，并适于通常用法，但是也引入了进一步的复杂性 — 两个 XML 文档虽然在逻辑上相等，但可能在确切文本比较中不同。象行定界符、空标记、在属性中使用十六进制而不是名称以及在特定情况下存在注释或注释变体这样的事情都可以成为文档的逻辑结构不受影响而实际彼此不同的实例。规范的 XML 规范描述了一种生成文档的物理表示（也成为范式）的方法，该范式解释允许的变体，以便如果两个文档具有同一范式，则认为两个文档在给定应用程序上下文中是逻辑相等的。
对于加密、特别是数字签名来说，这尤为重要，因为很明显，逻辑上相同的文本变体不应该表示文档的完整性及其发送方的认证是可疑的。用不同工具（譬如，解析器）生成不同文本（并因而生成不同消息摘要）进行处理时也可能发生这样的事。因此，在生成签名和验证计算期间，应该在范式上进行消息摘要。如果摘要匹配，这将确定：即使文本形式可能不同，它们在其上计算的范式也匹配。
XML 签名示例
可以将 XML 签名应用到任意数据内容。那些应用到相同 XML 文档中数据的签名称为封装或被封装的签名，而那些数据在签名元素外部的签名称为分离签名。清单 5 取自签名候选推荐文档，它是一个简单分离签名的实例。
清单 5. 一个简单分离签名的示例
[s01] <Signature Id="MyFirstSignature"
xmlns="http://www.w3.org/2000/09/xmldsig#">
[s02] <SignedInfo>
[s03] <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/
REC-xml-c14n-20010315"/>
[s04] <SignatureMethod Algorithm="http://www.w3.org/2000/09/
xmldsig#dsa-sha1"/>
[s05] <Reference URI="http://www.w3.org/TR/2000/REC-xhtml1-20000126/">
[s06] <Transforms>
[s07] <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-
20010315"/>
[s08] </Transforms>
[s09] <DigestMethod Algorithm="http://www.w3.org/2000/09/
xmldsig#sha1"/>
[s10] <DigestValue>j6lwx3rvEPO0vKtMup4NbeVu8nk=</DigestValue>
[s11] </Reference>
[s12] </SignedInfo>
[s13] <SignatureValue>MC0CFFrVLtRlk=...</SignatureValue>
[s14] <KeyInfo>
[s15a] <KeyValue>
[s15b] <DSAKeyValue>
[s15c] <p>...</p><Q>...</Q><G>...</G><Y>...</Y>
[s15d] </DSAKeyValue>
[s15e] </KeyValue>
[s16] </KeyInfo>
[s17] </Signature>
实际签名的信息是位于 s02 行和 s12 行之间，即 SignedInfo 元素。在签名的部分中包含用于计算 SignatureValue 元素的算法的引用，而那个元素本身位于签名部分之外（在 s13 行上）。s04 行上的 SignatureMethod 引用的是将规范的 SignedInfo 转换成 SignatureValue 所用的算法。它是密钥相关的算法和摘要算法（在这里是 DSA 和 SHA-1）的组合，可能还具有象填充这样的操作。KeyInfo 元素（在这里位于 s14 行和 s16 行之间 — 该元素是可选的）指出用来验证签名的密钥。
转换
正如前面所提到的，加密、签名、修改和可能进行的更多签名所发生的顺序有很多种可能性。用户可能需要向已经部分加密或部分签名的表单字段中输入更多数据，并且需要能够在不妨碍以后的验证和解密的前提下这样做。为解决这种情况，W3C 最近发布了一个有关 XML 签名的解密转换工作草案。（请参阅参考资料。）
下面这个示例摘自那个文档，它演示了如何建议文档接收方采用正确的解密和签名验证顺序。第一个代码段显示了要签名的文档部分 — order 元素；其中，第 7 行到第 11 行的 cardinfo 元素是关于个人和财务方面的详细信息，它是纯文本，但也存在一些加密数据（第 12 行）。
清单 6. XML 文档中的 order 元素
[01] <order Id="order">
[02] <item>
[03] <title>XML and Java</title>
[04] <price>100.0</price>
[05] <quantity>1</quantity>
[06] </item>
[07] <cardinfo>
[08] <name>Your Name</name>
[09] <expiration>04/2002</expiration>
[10] <number>5283 8304 6232 0010</number>
[11] </cardinfo>
[12] <EncryptedData Id="enc1"xmlns="http://www.w3.org/
2001/04/xmlenc#">...</EncryptedData>
[13] </order>
清单 7. 经过签名和进一步加密、且现在显示转换信息的 order 文档
[01] <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
[02] <SignedInfo>
[03] ...
[04] <Reference URI="#order">
[05] <Transforms>
[06] <Transform Algorithm="http://www.w3.org/2001/04/
xmlenc#decryption">
[07] <DataReference URI="#enc1"