利用XML Signature, 消息的完整性(Integrity)得到了保证。回顾之前提到的安全的三个基本概念--- Integrity, Confidentiality, Authentication, 现在该考虑消息的机密性的问题,虽然签名可以保证消息在传送的途中没有被篡改,但是并不能避免它被偷取。如果消息没有经过加密,那么某个敏感的信息就会被泄漏。与XML Signature类似,结合了XML技术和传统加密技术而产生的XML Encryption,也并不仅仅是加密XML文件那么简单,它提供了以下的功能:
1. 加密整个XML文件。
2. 加密XML文件中的某个元素。
3. 加密XML文件中某个元素的内容。
4. 加密非XML格式的资源。(例如一张JPEG图片)。
5. 加密已经过加密的内容。
XML Encryption的结构如下所示:
<EncryptedData (Id)? (Type)? (MimeType)? (Encoding)?>
(<EncryptionMethod/>)?
(<ds:KeyInfo>
(<ds:KeyName>)?
(<ds:RetrievalMethod>)?
(<ds:*>)?
(<EncryptedKey>)?
(<AgreementMethod>)?
</ds:KeyInfo>)?
<CipherData>
(<CipherValue>)?
(<CipherReference (URI)?>)?
</CipherData>
(<EncryptionProperties>)?
</EncryptedData>
(x)? 代表x出现0-1次 (x)+ 代表x出现1-n次 (x)* 代表x出现0-n次
与XML Signature不同,XML Encryption更加体现了自包含的性质,它不象XML Signature通过引用对某个资源签名,而是在原资源的位置上创建一个新的EncryptedData元素完全的替代原资源(使用CipherReference除外)。也是因为这个原因,你不可能象XML Signature那样在一个Signature元素中对多个资源签名,有几个需要加密的资源就有几个EncryptedData元素替代它们。
EncryptedData元素是原资源经过XML Encryption作用后的结果,将替代原资源。Type属性有两个合法值: element, content. 它们用于区别是否加密tag(标签)。如果Type设为element将加密整个元素包括tag在内, 而设为content时只对元素中的内容加密。
EncryptionMethod元素指定加密将使用的算法。
CipherData元素中的内容为原资源加密后的结果,可以用两种形式表示,通常使用CipherValue,而CipherReference类似于XML Signature的Reference元素,往往用于对外部资源(jpeg文件)的加密。
EncryptionProperties元素用于为加密的数据添加一些额外的信息,比如加密发生的时间。
KeyInfo元素描述加密所使用的密钥。这里的KeyInfo是借用的XML Signature下的KeyInfo元素。在签名的时候,大多使用非对称密钥,即利用私钥产生签名,然后将公钥信息放在KeyInfo元素中,这样消息的接受方就可以直接使用公钥来验证签名。但是在加密的时候,通常使用的是对称密钥,如果此时把密钥的信息直接放在KeyInfo中显然是不安全的。此时有以下几种方法:
1. 不使用KeyInfo元素,假定消息交换已经约定好了加密使用的密钥。
2. 在KeyInfo中指定一个标识(Identity),假定消息接受方已经拥有了解密所需的密钥,通过这个标识,消息接受方接可以定位到此次解密所需要的密钥。
3. 使用消息接受方的公钥加密此次加密消息所使用的对称密钥,消息接受方利用自己唯一拥有的私钥解密出加密消息使用的密钥。
4. 通过key agreement protocol获得密钥(较少使用)。
基于以上几种方法,下面对KeyInfo元素做具体介绍:
KeyName: 方法2中的一种形式,通过指定一个标识来获得解密所需的密钥。
RetrievalMethod: 方法2中的另一种形式,通过一个URI指向解密所需的密钥, 比如指向信息中另一段被加密的内容,而那段内容可以方便的被解密。
EncryptedKey: 为了使用第三种方法,XML Encryption为KeyInfo加入的扩展元素。通过非对称密钥技术来传递对称密钥, 综合了两种的优点,前提是消息加密方需拥有消息接受方的公钥。下面是使用该方法的一个例子。
AgreementMethod: 该元素使用key agreement protocol来获得密钥,极少使用故不做介绍。
<EncryptedData>
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmlsig#" />
<EncryptedKey>
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmlsig#"/>
<ds:X509Data>
<ds:X509SubjectName>
o=MyCompany,ou=Engineering,cn=Dave Remy
</ds:X509SubjectName>
</ds:X509Data>
</ds:KeyInfo>
<CipherData>
<CipherValue>. . .</CipherValue>
</CipherData>
</EncryptedKey>
</ds:KeyInfo>
<CipherData>
<CipherValue>. . .</CipherValue>
</CipherData>
</EncryptedData>
从上面的例子中可以看出EncryptedKey 和EncryptedData 具有类似的结构,其实它们本来就是同一类型(EncryptedType),一个用于加密数据,一个用于加密密钥(密钥就是一种特殊的数据)。它们之间的关系就象面向对象中的sub class和abstract class。EncryptedKey 和EncryptedData是EncryptedType的子类,而EncryptedType是不能具体存在的。因此EncryptedKey可以独立于EncryptedData存在,甚至EncryptedKey还可以象EncryptedData那样在子元素中嵌套EncryptedKey或EncryptedData。
了解了这个特性,就可以避免在两段使用相同密钥加密的消息中重复包含一个复杂的EncryptedKey。利用ReferenceList元素可以在密钥中引用到使用该密钥的不同地方,避免重复。
<Employee>
<Name>Dave Remy</Name>
<SocialSecurityNumber>
<EncryptedData id="socsecnum" Type="http://www.w3.org/2000/09/xmldsig#content">
<EncryptionMethod Algorithm=". . ." />
<CipherData>
<CipherValue>. . .</CipherValue>
</CipherData>
</EncryptedData>
</SocialSecurityNumber>
<Salary>
<EncryptedData id="salary" Type="http://www.w3.org/2000/09/xmldsig#content">
<EncryptionMethod Algorithm=". . .">
<CipherData><CipherValue>. . .</CipherValue></CipherData>
</EncryptedData>
</Salary>
<EncryptedKey>
<EncryptionMethod Algorithm=". . ." />
<CipherData>
<CipherValue>. . .</CipherValue>
</CipherData>
<ReferenceList>
<DataReference URI="#socsecnum" />
<DataReference URI="#salary" />
</ReferenceList>
</EncryptedKey>
</Employee>
通过以上方法,可以通过EncryptedKey中的ReferenceList定位到使用该密钥的不同信息段,但是这是一个单向引用,为了增加可读性,以及方便XML Encryption Processor处理还可以通过CarriedKeyName元素来实现双向引用,在WS-Security中也有类似的实现,示例如下:
<Employee>
<Name>Dave Remy</Name>
<SocialSecurityNumber>
<EncryptedData id="socsecnum" Type="http://www.w3.org/2000/09/xmldsig#content">
<KeyInfo>
<KeyName>Jothy Rosenberg</KeyName>
</KeyInfo>
<EncryptionMethod Algorithm=". . ." />
<CipherData>
<CipherValue>. . .</CipherValue>
</CipherData>
</EncryptedData>
</SocialSecurityNumber>
<Salary>
<EncryptedData id="salary" Type="http://www.w3.org/2000/09/xmldsig#content">
<EncryptionMethod Algorithm=". . .">
<CipherData>
<CipherValue>. . .</CipherValue>
</CipherData>
</EncryptedData>
</Salary>
<EncryptedKey>
<EncryptionMethod Algorithm=". . ." />
<CipherData>
<CipherValue>. . .</CipherValue>
</CipherData>
<ReferenceList>
<DataReference URI="#socsecnum" />
<DataReference URI="#salary" />
</ReferenceList>
<CarriedKeyName>Jothy Rosenberg</CarriedKeyName>
</EncryptedKey>
</Employee>
与XML Signature相比而言,XML Encryption的创建(加密)和验证(解密)过程要简单的多。简要介绍如下:
加密过程:
1. 选择一个加密算法
2. 选择一个加密用的密钥,如果需要将密钥的有关信息展示给消息接受方。
3. 在加密前,将待加密的资源转换为字符流的格式。
4. 使用选择的密钥和算法加密经过串行化的原始消息。
5. 设置加密的类型(Content还是Element?)。
6. 根据结果和以上的选项创建出EncryptedData元素,替代原来的资源。
解密过程:
1. 将CipherValue元素的内容抽取出来。
2. 从EncryptionMethod的Algorithm中获得加密所用的算法。
3. 获得加密的类型(Content还是Element?)。
4. 通过KeyInfo中的信息取得密钥。
5. 根据以上信息将密文解密获得原始信息。
系列文章
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架