<order>
<purchase>
<item quantity="1">Def Leppard: Pyromania</item>
</purchase>
<shipping>
<to>Shawn Farkas</to>
<street>One Microsoft Way</street>
<zip>98052</zip>
</shipping>
<payment>
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
xmlns="http://www.w3.org/2001/04/xmlenc#"
>
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/
xmlenc#aes256-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/
xmlenc#kw-aes256" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>billing</KeyName>
</KeyInfo>
<CipherData>
<CipherValue>
Sce6lLD+u2f8HzPFyuGxTF32z4mb2ugql3JuJIPAqIP98iYs+Muhqg==
</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>FXKC(3 lines of Base64 text)ApqQt</CipherValue>
</CipherData>
</EncryptedData>
</payment>
</order>
图13 加密了支付信息的CD订单
请观察一下加密数据,您可以看到我们已经描述的各个部分。首先,EncryptionMethod元素显示了AES-256的URI,这意味着该文档用带有256位密钥的AES算法(由RijndaelManaged类实现)加密。Encrypt方法为您生成一个随机的会话密钥;该密钥在KeyInfo元素中加密。通过观察EncryptedKey元素,您可以看到它是用RSA算法并借助于一个名为“billing”的密钥加密的。CipherData元素存放了该密钥的加密值。在KeyInfo的后面是包含加密内容(原来的付款元素)的CipherData。解密刚才说明的文档很容易,这要归功于EncryptedXml的DecryptDocument方法。首先,加载含有加密内容的文档:
// Assumes the encrypted order is in encrypted.xml
XmlDocument doc = new XmlDocument("encrypted.xml");
EncryptedXml exml = new EncryptedXml(doc, documentEvidence);
接下来,设置密钥-名称映射,如下所示:
// Set up the key mapping. Assumes a method called GetBillingKey
// that returns the RSA key for the billing department.
RSA billingKey = GetBillingKey();
exml.AddKeyNameMapping("billing", billingKey);
最后,调用DecryptDocument。该方法将负责解密密码文本,并且将加密的XML替换为它的解密内容。
// Decrypt the encrypted XML in the document
exml.DecryptDocument();
在幕后,加密引擎将在调用DecryptDocument时寻找任何EncryptedData元素,在这种情况下,它只找到付款元素下面的那个元素。在找到该元素以后,它将查看KeyInfo子句并且看到它持有加密的256位AES密钥。加密密钥的KeyInfo将显示它是用名为billing的RSA密钥加密的。然后,它检查密钥映射表以寻找名为billing的密钥。我们为一个名为billing的密钥添加了一个密钥映射,因此引擎随后将解密加密密钥。既然引擎具有密钥,那么它将解密CipherData。然后,用解密的CipherData的结果来替换EncryptedData元素。当DecryptDocument被调用时,引擎将对它在该文档中找到的每个EncryptedData元素执行这一过程。
X.509支持
安全方面的难题之一是信任。在网络中安全地分发和存储受信任的公钥并不容易,但是,Windows提供了大量基础结构来解决该问题。加密API(Cryptographic API,CAPI)提供了对分发、操纵和存储X.509证书的支持。CAPI提供的支持也称为公钥基础结构(Public Key Infrastructure,PKI)。
X.509证书提供有关密钥的其他信息。证书指定了密钥的颁发者、密钥的接收者、证书何时有效以及实际的密钥信息。证书是由证书颁发机构(Certificate Authorities,CA)颁发的,CA是您给予信任以担保证书持有者身份的实体(例如,某个外部公司或您所在公司的IT部门)。如果您具有一个有效证书,它包含由您信任的CA颁发的属于您的计帐部门的公钥,则您可以确保该公钥确实是计帐部门的。
通过Windows PKI支持,您可以安全地在计算机上的证书存储器中存储证书,在网络计算机上的证书存储器中添加和移除证书,在网络计算机上添加和移除受信任的CA,获得和验证有关单个证书的信息等等。例如,这使您可以将证书(包含您所在公司计帐部门的公钥)分发到公司网络中的所有计算机。在.NET Framework 1.x中,必须调用非托管API才能利用该支持的大部分功能。在.NET Framework 2.0中,可以在托管代码中通过X509CertificateEx类和相关的类使用这些API中的大多数API。XML签名类直接支持X509CertificateEx类。要用证书创建XML签名,只需从该证书的PrivateKey属性中获得私钥,然后将其用作SignedXml对象的签名密钥。
// Use the private key from the certificate. Assumes a SignedXml
// object in sig and an X509CertificateEx object in cert.
sig.SigningKey = cert.PrivateKey;
当然,该证书必须具有相关联的私钥,否则PrivateKey属性返回null。您还可以通过使用KeyInfoX509Data类将X.509证书信息添加到已签名的KeyInfo元素中,如以下代码所示:
// Add X.509 certificate info to the KeyInfo element. Assumes a
// SignedXml object in sig and an X509CertificateEx in cert.
KeyInfoX509Data keyInfoX509 =
new KeyInfoX509Data(cert, X509IncludeOption.EndCertOnly);
sig.KeyInfo.AddClause(keyInfoX509);
要验证用证书的私钥签名的XML签名,可以调用SignedXml类的CheckSignature方法的新重载,该新重载采用一个X509CertificateEx对象和一个布尔值。如果该布尔值被设置为true,则该方法将针对证书中的公钥验证签名,并且通过检查密钥使用率以及生成到受信任的根颁发者的链条来验证该证书。
// Check the signature against the cert and verify the cert. Assumes a
// SignedXml object in sig and an X509CertificateEx object in cert.
bool verified = sig.CheckSignature(cert, true);
还可以使用不带任何参数的CheckSignature方法来验证签名,但是它不会同时验证X.509证书(如果使用了一个这样的证书对XML进行签名)。作为一个单独的步骤,您必须根据KeyInfo重新创建X509CertificateEx对象并对其进行验证。有关出于测试目地创建X.509证书的更多信息,请参阅.NET Framework SDK文档中的证书创建工具(Makecert.exe)主题。
.NET Framework 2.0向签名引擎中添加了几个新的转换和规范化算法。这些算法包括Exclusive C14N规范化算法、XML解密转换和LTA转换。图14包含.NET Framework 2.0签名引擎中提供的转换和规范化算法的完整表格。
| Class | Description |
| XmlDecryptionTransform | Decrypts encrypted XML |
| XmlDsigBase64Transform | Decodes base64 encoded data |
| XmlDsigC14NTransform | Performs C14N canonicalization (see http://www.w3.org/TR/xml-c14n for more information) |
| XmlDsigEnvelopedSignatureTransform | Removes an enveloped signature from a document |
| XmlDsigExcC14NTransform | Performs exclusive C14N canonicalization (see http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718 for more information) |
| XmlDsigXPathTransform | Applies an XPath filter to the input XML |
| XmlDsigXsltTransform | Applies an XSLT transform to the input XML |
| XmlLicenseTransform | Implements the LTA transform |
| XmlDsigC14NWithCommentsTransform | Performs C14N canonicalization, but leaves comments in the canonicalized XML |
| XmlDsigExcC14NWithCommentsTransform | Performs exclusive C14N canonicalization, but leaves comments in the canonicalized XML |
图14 转换和规范化算法库
小结
我们在这里讨论了XML签名标准的基础知识以及它在.NET Framework 1.x中是如何实现的。我们还讨论了.NET Framework 2.0中的一些新功能,包括对XML加密标准的支持以及对XML签名的X.509证书集成。通过这些积木技术,可以使用标准与其他应用程序互操作,并且将标准支持内置到您自己的应用程序中。
作者简介
Mike Downen 是 Microsoft 的 CLR 安全小组的项目经理,并从事代码访问安全性、加密术和新的 ClickOnce 安全模型方面的工作。您可以通过 mdownen@microsoft.com 与 Mike 联系。
Shawn Farkas 是 Microsoft 的 CLR 安全小组的见习软件设计工程师。他从事 ClickOnce、加密技术和 IL 验证方面的工作。请在 http://blogs.msdn.com/shawnfa 查看他的网络日记。
相关专题
- WPF的Attached属性 (0次浏览)
- WPF,将颠覆的设计世界? (0次浏览)
- Windows是否已经变成了一个怪物? (0次浏览)
- Windows2008用RODC保证分支机构安全 (0次浏览)
- Windows2008的NLB配置攻略 (0次浏览)
- Windows SharePoint Services 和 SharePoint P (0次浏览)
- Windows Forms中实现统一的数据验证(一) (0次浏览)
- Windows API一日一练:DrawText函数 (0次浏览)
- Win2008初次体验的几个心得 (0次浏览)
- WEB应用数据库访问的优化 (0次浏览)



