1、通过 XML 签名和加密更安全地交换数据作者:Mike Downen、Shawn Farkas相关技术:XML、.NET Framework、C#、安全性摘要 XML 签名和 XML 加密标准目前被广泛地用作构建快(building-block)技术。本文解释了 XML 签名和 XML 加密标准,并且说明了如何通过.NET 使用它们。注:本文的某些部分基于 .NET Framework 2.0 的预发布版本。与这些部分有关的所有信息都有可能更改。XML 签名和 XML 加密标准目前被广泛地用作积木(building-block)技术。Microsoft Office InfoPath 使用 X
2、ML 签名对部分或整个表单进行签名。Web 服务使用 XML 签名对SOAP 消息进行签名,并且使用 XML 加密技术对它们进行加密。基于 ClickOnce 的应用程序的 XML 清单(Visual Studio 2005 中的新增功能)也使用 XML 签名。.NET Framework 1.x包含 XML 签名标准的对象模型,而.NET Framework 2.0 则添加了其他支持,同时还添加了XML 加密的对象模型。本文解释了 XML 签名和 XML 加密标准,并且说明了如何通过.NET 使用它们。有关实际的 XML 签名规范,请参阅位于 http:/www.w3.org/TR/xmld
3、sig-core的 W3C 标准。数字签名在深入探讨 XML 签名标准之前,让我们回顾一下数字签名的基础知识。因为防止恶意用户在传输期间改变消息很重要,所以数字签名保护数据的完整性,并且可以检测数据在到达接收地的途中受到的任何更改。因为能够标识发送方也很重要,所以消息通常使用发送方的私有(秘密)密钥进行签名,并且用相应的公钥进行验证,从而使接收者在知道发送方的公钥时可以确认发送方的标识。这可以防止恶意用户通过尝试作为已知的发送方发送消息,或者通过截获来自已知发送方的消息并将其替换为他们自己的消息(一种中间人形式的攻击),冒充已知的发送方。要创建数字签名,首先需要使用加密哈希函数来对需签名的消息
4、进行哈希运算。对于任何长度的输入,加密哈希函数都会返回固定长度的位组,称为哈希值。该哈希值无法容易地重新转换为原来的输入。即使输入中只有一个位发生更改,哈希值也会以不可预知的方式更改,因此无法仅仅通过查找类似的哈希值来找到与原始输入类似的输入。一个常用的哈希函数是SHA-1,它可以产生 160 位的哈希值。下一个步骤是使用签名算法和您的私钥对该哈希值进行签名,以产生签名值。您用您的私钥创建该签名,以便具有您的公钥的其他人可以对其进行验证(本文稍后将对此进行详细讨论)。RSA 是一种流行的用于签名的加密算法。在您将消息和该签名发送给接收者之后,验证过程开始。收到的消息被在签名时使用的相同哈希函数
5、用来进行哈希运算;然后,通过将签名值以及公钥和计算得到的哈希一起传递给签名算法,对签名值进行验证。如果计算得到的哈希与签名哈希相匹配,则签名有效。如果这两个哈希不匹配,则表明数据或签名已经更改,因此不能确保数据的完整性。还可以使用密钥哈希算法签名和验证数据,但是这超出了本文讨论的范围。.NET Framework 已经为所有种类的哈希、加密/解密和签名/验证算法包含了一组丰富的类。有关这些类的详细信息,请参阅 .NET Framework SDK 文档以及由 Brian LaMacchia 等人编写的NET Framework Security (Addison-Wesley, 2002)。X
6、ML 签名基础知识您可以使用 XML 签名对任何种类的数据进行签名,这些数据包括 XML 文档的某个部分、其他 XML 文档或任何格式的其他数据。但是,实际上,XML 签名最常用于对以 XML 表示的其他数据进行签名。XML 签名标准还非常灵活,它允许您在签名之前对数据进行筛选和转换,并且使您可以精确地选择要签名的内容以及签名方式。一个简单的文档:HelloWorld经过签名的文档:HelloWorldcbPT0951Ghb2G3UjpVjWw+7q0Bc=IoEwS(3 lines of Base64 text)XSo=图 1 签名前后的简单 XML 文档让我们考察一个简单的 XML 签名方
7、案:对整个文档进行签名并且包含签名(参见图 1)。请注意已经被添加到文档中的 Signature 元素,该元素包含 XML 签名。让我们看一下每个元素所包含的内容:SignedInfo该元素的子元素包含有关所签名的内容以及签名方式的所有信息。签名算法实际上应用于该元素及其所有子元素以生成签名。CanonicalizationMethod该元素指定了用于 SignedInfo 元素以便将 XML 规范化的规范化(C14N) 算法。我们将在下文中讨论 C14N。SignatureMethod该元素指定了该签名的签名算法。在该示例中,签名算法是带有RSA(用于对产生的哈希值进行签名)的 SHA-1(
8、用于哈希运算)。Reference这些元素指定了将要签名的数据以及在哈希运算之前应当如何对该数据进行处理。URI 属性(它表示统一资源标识符)标识要签名的数据,而 Transforms 元素(稍后描述)指定在进行哈希运算之前如何处理数据。在该示例中,我们将使用特殊的 URI空字符串,它指定包含签名的文档是要包含在签名中的数据。XML 签名标准对 Reference 数据使用间接签名机制。该标准不是对 Reference 中的所有数据进行哈希运算然后加密哈希值,而是使用由 Reference 的 DigestMethod 元素所指定的算法对每个 Reference 的数据进行哈希运算,然后将哈希
9、值存储到 Reference 的 DigestValue 元素中。接下来,对 SignedInfo 元素和它的所有子元素(包括 Reference 元素)进行哈希运算;哈希值被加密以生成签名。因此,您实际上是对 Reference 元素中所引用数据的哈希的哈希进行签名,但是该方案仍然可以保护数据的完整性。图 2 和图 3 在匹配的 XML 旁边显示了签名和验证过程。Transforms每个 Reference 元素都可以具有零个或更多个为它指定的转换。这些转换按照它们在 XML 中列出的顺序应用于该 Reference 的数据。转换使您可以在对 Reference的数据进行哈希运算之前对该数据
10、进行筛选或修改。在该示例中,我们将使用包封式签名转换,该转换选择了包含文档中除 Signature 元素以外的所有 XML。我们必须从将被签名的数据中移除 Signature 元素,否则,当我们存储签名值时,可能会修改我们尝试签名的数据。我们将在下文中详细讨论转换。SignatureValue该元素包含通过签名 SignedInfo 元素及其所有子元素而计算得到的签名值。现在,让我们讨论用于创建签名的处理模型(参见图 2)。首先,对于签名中的每个Reference 元素: 按照转换在 Transforms 元素下面出现的顺序,将 Transform 元素中指定的每个转换算法应用于 Refere
11、nce 的数据。 使用 Reference 的 DigestMethod 元素所指定的哈希算法对经过转换的数据进行哈希运算。 在 Reference 的 DigestValue 元素中存储产生的哈希值。下一个步骤是使用在签名的 CanonicalizationMethod 元素中指定的算法规范化SignedInfo 元素及其子元素。然后,使用在签名的 SignatureMethod 元素中指定的算法对SignedInfo 元素及其子元素进行签名。签名值被存储在 SignatureValue 元素中。签名验证是刚刚描述的过程的逆过程。首先,必须使用 CanonicalizationMethod
12、元素中指定的 C14N 算法规范化 SignedInfo 元素及其子元素。然后,必须针对 SignedInfo 元素及其子元素验证 SignatureValue 元素中存储的签名值。最后,对于签名中的每个 Reference 元素: 按照转换在 Transforms 元素下面出现的顺序,将 Reference 的 Transform 元素中指定的每个转换算法应用于 Reference 的数据。 使用 Reference 的 DigestMethod 元素所指定的哈希算法对 Reference 的经过转换的数据进行哈希运算。 将计算得到的哈希值与 DigestValue 元素中存储的值进行比较。
13、如果签名验证成功,并且每个 Reference 的哈希值与签名中存储的哈希值相等,则 XML签名有效。否则,或者由 Reference 元素之一引用的数据已经更改,或者 Signature 元素已经更改。嵌入到由其签名的文档中的签名称为信封签名。using System.Security.Cryptography;using System.Security.Cryptography.Xml;/ Also, add a reference to System.Security.dll/ Assume the data to sign is in the data.xml file, load i
14、t, and/ set up the signature object.XmlDocument doc = new XmlDocument();doc.Load(“data.xml“);SignedXml sig = new SignedXml(doc);/ Make a random RSA key, and set it on the signature for signing.RSA key = new RSACryptoServiceProvider();sig.SigningKey = key;/ Create a Reference to the containing docume
15、nt, add the enveloped/ transform, and then add the Reference to the signatureReference refr = new Reference(“);refr.AddTransform(new XmlDsigEnvelopedSignatureTransform();sig.AddReference(refr);/ Compute the signature, add it to the XML document, and savesig.ComputeSignature();doc.DocumentElement.App
16、endChild(sig.GetXml();doc.Save(“data-signed.xml“);using System.Security.Cryptography;using System.Security.Cryptography.Xml;/ Also, add a reference to System.Security.dll/ Load the signed dataXmlDocument doc = new XmlDocument();doc.PreserveWhitespace = true;doc.Load(“data-signed.xml“);/ Find the Sig
17、nature element in the documentXmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable();nsm.AddNamespace(“dsig“, SignedXml.XmlDsigNamespaceUrl);XmlElement sigElt = (XmlElement)doc.SelectSingleNode(“/dsig:Signature“, nsm);/ Load the signature for verificationSignedXml sig = new SignedXml(doc)
18、;sig.LoadXml(sigElt);/ Verify the signature, assume the public key part of the/ signing key is in the key variableif (sig.CheckSignature(key)Console.WriteLine(“Signature verified“);else Console.WriteLine(“Signature not valid“);您已经了解了如何创建和验证包封式签名,它们很常用并且在对整个 XML 文档进行签名时很方便,而且 XML 签名标准还使您可以通过在 Referen
19、ce 元素中指定不同的 URI 对其他数据进行签名。因此,让我们接下来考察一下不同类型的引用。引用除了包封式引用(其 URI 属性为空字符串的 Reference 元素)以外,在 XML 签名标准中还定义了其他两个宽泛类型的引用:对分离数据的引用以及通过 ID 对 XML 数据进行的引用。分离数据位于包含签名的 XML 文档的外部,这些引用可以指向另外一个 XML 文档或任何其他类型的资源。当您在一个签名中对多个资源(例如,一个 XML 文档以及由该文档引用的其他一些文件)进行签名时,通常会使用该类型的引用。下面的 XML 代码片段显示了分离引用的一个示例:cbPT0951Ghb2G3UjpV
20、jWw+7q0Bc=为了使用 Framework 中的类来创建分离引用,只需在创建引用对象时将该引用的 URI 设置为资源的 URI,然后 将该引用添加到签名中,如下所示:/ Create a Reference to detached data, assume a SignedXml object in sigReference refr = new Reference(“http:/ ID 对 XML 数据进行的引用指向包含签名的文档内部或签名本身内部的 XML。对于这些引用,签名引擎寻找其 ID 属性与引用中的 URI 匹配(不包括 #)的元素。以下为一个基于ID 的引用的示例:cbPT
21、0951Ghb2G3UjpVjWw+7q0Bc=如果 ID 为“myData”的元素位于包含签名的文档中,则该引用是完整的,并且签名引擎将在处理该签名时找到它。您通常使用该类型的引用将签名的作用范围限制到示例文档的特定部分。例如,在文档处理应用程序中,审阅者通常只对他审阅的 XML 文档部分(而不是整个文档)进行签名。该标准还允许您向 Object 元素中的签名添加任意数据。Object 元素的 XML看起来类似于以下代码行:Your XML goes here要创建基于 ID 的引用(该引用指向包含签名的文档中已经存在的元素),请添加如下所示的代码:/ Create a Reference
22、to XML data in the containing document,/ assume a SignedXml object in sigReference refr = new Reference(“#myData“);sig.AddReference(refr);如果基于 ID 的引用指向了签名中的一个 Object 元素,则除了添加该引用以外,还必须向签名中添加一个 DataObject,如刚才显示的代码中所示。数据对象可以包含您传入的任何XML。/ Adds a DataObject with an Id of “#myData“ to the signature, assum
23、e a / SignedXml object in sig, and xml data of type XmlNodeList in dataDataObject dobj = new DataObject();dobj.Id = “myData“; / Note: no #dobj.Data = data; / XML Data of the Objectsig.AddObject(dobj);您通常使用指向 Object 元素的引用来对有关签名的元数据进行签名,例如,签名者的唯一标识符或有关该签名的其他一些信息。转换转换通过允许您在生成引用的数据的哈希值之前修改该数据,使您可以对已签名的内
24、容进行更多的控制。例如,信封式签名转换在对 XML 文档进行签名之前会移除 Signature 节点。引用可以指定任何数量的转换,这些转换按照在 Transforms 元素中指定的顺序而做用。.NET Framework 中的类除了支持我们前面提到的信封式签名转换以外,还支持下列转换: 任何规范化算法都可以用作转换。 通过 Base64 转换可以对 Base64 编码数据进行解码。 通过 XSLT 转换,可以在对 XML 数据进行签名之前,向其应用 XSLT 样式表。要应用的XSLT 样式表被指定为 Transform 元素下的 XML。 通过 XPath 转换可以用 XPath 表达式筛选
25、XML 数据。XPath 表达式被指定为 Transform 元素下的 XPath 元素的文本内容。需要注意的是,XPath 转换充当筛选器,而不是充当在作为输入传递的 XML 中选择节点的手段。该转换针对作为输入传递给该转换的每个节点计算 XPath 表达式,结果被转换为布尔值。输入节点将被考虑以便传递计算,并且如果计算的结果为 true,则输入节点将被包含在转换的输出中。考虑转换的以下 XML 输入:Some dataMore dataEven more data假设我们只希望选择 “b”节点进行签名。带有 XPath 表达式“ancestor-or-self:b”的XPath 转换将返回
26、以下节点集(它正是我们所需要的):Some dataEven more data该 XPath 表达式的 Transform 元素看起来类似于下面的代码片段:ancestor-or-self:b要在签名时以编程方式创建转换,请创建某个转换对象的实例,适当设置它的属性,并且将其添加到它所应用于的引用。以下示例将上一个示例中使用的 XPath 转换添加到某个引用中,以便创建转换:/ Add an XPath transform to a reference./ Assume a Reference object in refr XmlDocument doc = new XmlDocument()
27、;doc.LoadXml(“ancestor-or-self:b“);XmlDsigXPathTransform xptrans = new XmlDsigXPathTransform();xptrans.LoadInnerXml(doc.ChildNodes);refr.AddTransform(xptrans);规范化规范化的目的是为两个逻辑上相同但可能不是由相同的文本表示的 XML 片段产生相同的XML 数据。例如,请观察下面两个代码片段。它们在逻辑上是相同的;它们的不同之处仅仅在于文本表示。但是如果您要对它们按原样进行哈希运算,则得到的哈希值将是不同的:Some textMore te
28、xtSome textMore text要避免该问题,该标准中指定的默认规范化算法将执行很多任务,包括消除开始和结束标记中的空白以及将空元素转换为开始/结束标记对。但是,它不会更改元素内容中的任何空白。所执行操作的完整列表可以在 Canonical XML(位于 http:/www.w3.org/TR/xml-c14n)中得到。签名引擎在必要时自动规范化数据,以便符合 W3C 标准。特别地,每当签名引擎需要将XML 数据转换为二进制数据以便进行哈希运算时,都会规范化该数据。例如,当它准备对SignedInfo 元素及其子元素进行签名时,就会发生这种情况。当它准备引用或转换的输出以便进行签名时,
29、也可能发生这种情况。例如,如果您使用基于 ID 的引用(指向包含签名的文档中的其他 XML 数据),并且该引用没有与其相关联的转换,则签名引擎在对该引用的 XML数据进行哈希运算之前将规范化该数据。密钥管理XML 签名标准提供了 KeyInfo 元素,帮助进行密钥管理。该元素可以存储密钥名称、密钥值、密钥检索方法或证书信息,以帮助接收方验证签名。该标准没有指定应当如何信任以及是否应当信任 KeyInfo 元素中的任何信息。如果发送方和接收方共享一个受信任密钥列表,或者如果您发现了其他某种用于将密钥名称映射到密钥的方法,则 KeyInfo 元素可能很有用。.NET Framework 1.x 具
30、有一些对密钥名称、值和检索方法的支持, .NET Framework 2.0还包含对 X.509 证书的支持。让我们假设发送方和接收方共享一个密钥列表,接收方对于他期望从其接收消息的每个发送方都具有一个公钥。签名应用程序可以添加以下代码,以便向签名中添加 KeyInfo 元素:/ Adds an KeyInfo element with RSA public key information to the / signature. / Assumes a SignedXml object in sig, and an RSA object in key.KeyInfo ki = new KeyI
31、nfo();ki.AddClause(new RSAKeyValue(key);sig.KeyInfo = ki;该代码应当在调用 ComputeSignature 之前添加。它将在签名中产生一个 KeyInfo 元素,该元素看起来类似于以下代码:4LfG(2 lines of Base64 text)2Fr=AQAB这表示用来对 XML 文档进行签名的 RSA 公钥。接收方应用程序应当将该密钥与受信任密钥列表进行比较,如果该公钥不在列表中,则不应当信任文档。否则,攻击者就可以在传输过程中替换已经签名的文档,并且用另外一个密钥对其进行签名。如果签名包含与此类似的RSAKeyValue,则验证代
32、码可以调用 SignedXml 类的 CheckSignature 方法(它不采用任何参数),并且.NET Framework 将根据 RSAKeyValue 元素计算出该密钥。下面是一个示例:/ Verify a signature that includes RSAKeyInfo or DSAKeyInfo./ Assume a SignedXml object in sig.bool verified = sig.CheckSignature();签名配置文件伴随 XML 签名的灵活性而来的是一定数量的风险。因为转换是如此灵活,所以可能很难精确计算出签名涵盖了哪些数据,这可能导致意外的或
33、不安全的结果。这些签名配置文件可以通过指定应用程序所支持的签名形式,在该方面提供帮助。尽管没有相应于签名配置文件的标准,但签名配置文件起码应当指定应用程序期望签名具有的引用和转换,以便您可以确保所期望签名的数据确实进行了签名。签名配置文件还可以包含其他数据,例如,期望签名数据具有的签名算法或密钥大小。应用程序应当检查并强制它所创建和验证的那些签名符合该应用程序所支持的签名配置文件。要更好地理解配置文件为什么如此重要,请考虑图 1。假设您要编写接受XML 签名数据的应用程序,但是您的应用程序只期望使用信封式签名转换而非任何其他转换的签名。现在,有人向您发送了带有额外 XPath 转换的签名文档,
34、如图 6 所示。HelloWorldancestor-or-self:amN4R0653F4ethOiTBeAu+7q0Be=X4Ie(3 lines of Base64 text)nP3=在示例中,签名只涵盖示例文档中的“a” 元素。如果您刚刚加载了该文档并且调用了SignedXml 类的 CheckSignature 方法,则即使“b”元素未被该签名涵盖,该签名仍然可能验证,这是因为签名引擎将应用在该签名中指定的转换。如果应用程序依赖于该签名涵盖了“b”元素这一前提,则数据的完整性已经遭到损害。应用程序应当检验只有一个引用具有作为URI 的空字符串并且该引用具有一个转换信封式签名,从而验证
35、它所期望的签名配置文件。它会在验证签名时拒绝任何其他签名配置文件。一些用于检验该签名配置文件的示例代码显示在图 7 中。/ This method checks the signature profile for the signature/ in the supplied document. It ensures there is only one/ Signature element and only one enveloped reference with only/ one enveloped signature transformpublic bool CheckSignatureP
36、rofile(XmlDocument doc)/ Make sure there is only one Signature elementXmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable();nsm.AddNamespace(“dsig“, SignedXml.XmlDsigNamespaceUrl);XmlNodeList sigList = doc.SelectNodes(“/dsig:Signature“, nsm);if (sigList.Count 1)return false; /Wrong numbe
37、r of Signature elements/Make sure the Signature element has only one ReferenceXmlElement sigElt = (XmlElement)sigList0;XmlNodeList refList = sigElt.SelectNodes(“dsig:SignedInfo/dsig:Reference“, nsm);if (refList.Count 1)return false; /Wrong number of Reference elements/ Make sure the Reference URI is
38、 “XmlElement refElt = (XmlElement)refList0;XmlAttributeCollection refAttrs = refElt.Attributes;XmlNode uriAttr = refAttrs.GetNamedItem(“URI“);if (uriAttr = null) | (uriAttr.Value != “)return false; / Wrong type of reference/ Make sure the only tranform is the enveloped signature transformXmlNodeList
39、 transList = refElt.SelectNodes(“dsig:Transforms/dsig:Transform“, nsm);if (transList.Count != 1)return false; /Wrong number of Transform elementsXmlElement transElt = (XmlElement)transList0;string transAlg = transElt.GetAttribute(“Algorithm“);if (transAlg != SignedXml.XmlDsigEnvelopedSignatureTransf
40、ormUrl)return false; /Wrong type of transformreturn true;迄今为止,我们已经考察了 XML 签名标准的一些不同方面以及.NET Framework 中对它的支持。让我们将这些功能中的某些功能一起放到一个更为完整的示例中。假设您要编写一个应用程序以便交换 XML 形式的消息,并且您希望对该消息的全部内容进行签名。您还希望将一些有关签名者的 XML 数据作为对象添加到 Signature 元素中,以便只对该数据的 signerID元素进行签名。您的应用程序可以访问一个众所周知的密钥列表,因此您还将在签名中存储公钥信息,并且检验以确保该密钥在验
41、证期间映射到一个众所周知的密钥。用于签名和验证消息的代码包含在本文的完整代码下载中。用该代码对消息进行签名将产生如图 8 所示的 XML 签名。Some DataMore datacbPT0951Ghb2G3UjpVjWw+7q0Bc=ancestor-or-self:my:SignerIDmN4R0653F4ethOiTBeAu+7q0BeIoEwS.4LfG(2 lines of Base64 text)2Fr=AQABMike4815.NET Framework 2.0 中的新特性迄今为止讨论的所有 XML 签名特性在.NET Framework 1.x 和 2.0 中都可用。XML 加
42、密和 X.509 证书集成对于版本 2.0 而言是新增特性。通过 X.509 证书集成,可以更容易地将X.509 证书用于 XML 签名。通过新增的 X509CertificateEx 类和相关的类,可以更容易地操纵和使用证书,并且 XML 签名对象模型在适当的时候使用这些类。在本文的结尾,我们将对X.509 集成进行更详细的讨论。XML 加密是另外一个 W3C 标准。正如 XML 签名指定了有关创建 XML 形式的数字签名的格式和处理模型一样,XML 加密对如何加密 XML 形式的数据进行了标准化。XML 数字签名是通过 SignedXml 类驱动的,而 XML 加密是使用新的Encrypt
43、edXml 类执行的。尽管 XML 加密可以用来加密任意数据,但它最常用于加密其他XML。当以这种方式使用时,您将在文档的加密方式上拥有很多的灵活性。例如,可以用不同的密钥加密 XML 文档的不同节点,同时将某些节点保留为明文。而且,由于用EncryptedXml 类加密某些内容会产生 XML,因此您甚至可以加密已经加密的结果,该过程称为“超级加密” 。让我们考察一下一些已经加密的 XML(参见图 9)。一件可以立刻注意到的有趣的事情是,XML 加密标准对某些元素(包括 KeyInfo 元素)使用 XML 签名命名空间。一个简单的文档:HelloWorld经过加密的文档:recipient_p
44、ublic_key PrI6(3 lines of Base64 text)Dwy4= awcH(3 lines of Base64 text)NNqQ= EncryptedData 元素EncryptedData 是通过加密 XML 生成的根元素,并且它包含有关数据的所有信息。EncryptedData 包含三个主要的子元素:EncryptionMethod 指定用来加密数据的算法;KeyInfo 元素提供有关使用哪个密钥来解密数据的信息;CipherData 或 CipherReference元素则包含实际的加密信息。EncryptionMethod 元素指定用来加密和解密密码数据的算法,
45、这些算法由 URI 指定,就像 XML 签名标准一样。EncryptionMethod 同时用于加密数据和加密密钥,但并非每个算法都可以同时用于这两个场合。图 10 显示了每个算法可以用在哪个场合。请注意,高级加密标准(Advanced Encryption Standard,AES)还可用于 192 位和128 位密码;您只需在 URI 中更改密钥大小。EncryptedXml 类的 URI 属性 加密数据 加密密钥XmlEncAES256Url AES XmlEncAES256KeyWrapUrl DES XmlEncDESUrl XmlEncTripleDESUrl TripleDESX
46、mlEncTripleDESKeyWrapUrl RSA XmlEncRSA1_5Url 在加密或解密任何数据之前,加密引擎需要知道应当使用哪个密钥来加密和解密。可以用两种方式标识密钥,最容易的方式是为该密钥分配一个名称,并且在 KeyInfo 元素内部放置一个 KeyName 元素。解密文档的应用程序可以获得 KeyName 标记,并提供与给定的名称相匹配的密钥。该应用程序不仅提供密钥的名称,还可以将密钥作为 EncryptedKey 直接嵌入到KeyInfo 元素中。 EncryptedKey 与 EncryptedData 包含相同的元素:加密方法、用来解密该密钥的密钥以及构成加密密钥的
47、密码数据。加密密钥通常与命名密钥结合使用,以作为随机会话密钥。首先,生成一个随机会话密钥并使用它来加密 XML;然后,用需要解密文档的众所周知的命名密钥加密会话密钥本身;最后,将该命名密钥插入到加密会话密钥的 KeyInfo 元素中,并且将该加密会话密钥附加到加密数据中。图 9 中的示例说明了这一点。XML 数据的加密方法是 256 位的 AES,而 AES 算法的密钥也已经被加密。EncryptedKey 元素包含有关如何加密 AES 算法的密钥的信息,在该示例中,它是使用名为 recipients_public_key 的 RSA 密钥加密的。使用 XML 加密的应用程序必须将该名称映射到
48、实际的密钥。可以将实际的加密数据嵌入到 EncryptedData 元素中,或者将其放到单独的位置,然后从EncryptedData 中引用它。如果要将密码数据直接放到 EncryptedData 中,则会将其作为Base64 编码的二进制文件放到 CipherData 元素中。图 9 中的示例使用了一个 CipherData元素。另一个方案是将加密数据放到 EncryptedData 元素外部。可以将密码文本放在从该文档中的另一个元素到远程 Web 站点的任何位置。在这两种情况下,都将使用CipherReference 元素而不是 CipherData 元素(参见图 11)。CipherRe
49、ference 的位置 URI 格式 密码文本格式相同文档中 #order Base64 字符串远程 Web 站点 http:/ 二进制对远程 Web 站点的 CipherReferences 提出了一个有趣的安全方案。在解密 XML 的过程中,解密引擎必须转到任意 Web 站点并下载密码文本。由于要解密的文档可能不会受到与完成解密的代码同等程度的信任,因此应当在沙箱中完成该操作。这是通过向 EncryptedXml 对象提供它将在解析任何 CipherReferences 时使用的证据来完成的。通过沙箱可以更安全地执行代码,因为解密应用程序可能不具有与提供加密数据的站点相同的权限。例如,如果应用程序试图解密不受信任的站点,并且该不受信任的站点不能够访问位于安全的、受信任站点上的某些受信任的数据,则它可以通过包含密码引用,让解密应用程序为它访问该文件。由于.NET安全策略是以证据为中心的,因此所提供的证据通常