享受代码,享受人生

SOA is an integration solution. SOA is message oriented first.
The Key character of SOA is loosely coupled. SOA is enriched
by creating composite apps.
posts - 98, comments - 2396, trackbacks - 162, articles - 45
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

XML Encryption

Posted on 2006-04-16 09:47 idior 阅读(3137) 评论(7)  编辑 收藏

利用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. 根据以上信息将密文解密获得原始信息。

系列文章

Feedback

#1楼  回复 引用   

2007-04-26 21:20 by dengkun[未注册用户]
你好!读了您写的文章,觉得很好!想问一下用JAVA来实现XML加密,有没有
像签名一样现成的API。还是要自己写,解析XML,再加密?希望您能指导一下。我的邮箱是dengkun39@yahoo.com.cn

#2楼  回复 引用 查看   

2007-09-28 18:43 by EagleFish      
一定要再顶一下

当我看到楼主给出的EncryptedKey的实现的时候,真的是很爽啊。所谓“使用非对称密钥加密对称密钥,使用对称密钥加密信息”在小小的xml片段里一览无遗。

问一个很弱的问题:
客户端的非对称密钥对是什么时候产生的,又是什么时候把公钥告诉服务器的呢?是不是服务器替客户端生成一个密钥对,然后把这个密钥对存到数据库里,同时把私钥发送给客户端(怎么发送才能保证私钥不被窃取)?这是不是意味着我作为一个客户端,每当我在一个使用了ws-security进行安全验证的网站注册了之后,网站都会替我生成这样一对密钥,然后保存起来?

#3楼  回复 引用 查看   

2007-09-28 18:54 by EagleFish      
刚才我的表述可能比较乱,其实我主要是不太清楚客户端和服务端的“密钥握手过程”,即
1.密钥是在哪边产生的
2.在什么时候通过什么方式告诉对方的
3.平时保存在哪里
4.过期或被盗取了的话怎么通知对方

等等等等.....

#4楼[楼主]  回复 引用 查看   

2007-09-28 19:09 by idior      
@EagleFish
在B2C应用中,客户端通常使用服务方的公钥加密对称密钥。而不是说使用自己的私钥。因为使用x509证书是有一定成本的。
在B2B应用中,客户端才会有自己的公私密钥对,而这都是需要从CA那获得的。

谢谢你的支持!

#5楼  回复 引用 查看   

2007-09-28 19:51 by EagleFish      
@idior

非常感谢你的回复,言简意赅,解决了我不少困惑 :)
原来我们使用B2C业务的时候,只是安装一下网站的证书(这个证书就是网站的公钥,对吧?),根本不存在非对称密钥的问题......

#6楼  回复 引用 查看   

2008-07-17 16:06 by jillzhang      
根本不存在非对称密钥的问题......
------------------------------------
一个证书要么只有公钥
要么就是公钥+私钥
就这两种状态

私钥用于签名,公钥用于加密,所以公钥怎么不是非对称性加密算法的密钥了?

#7楼[楼主]  回复 引用 查看   

2008-07-18 14:20 by idior      
@jillzhang

对称与非对称是就整个加密,解密过程而言的。

原文 --A-> 密文 -B--> 原文

就是说B操作应该是A操作的逆操作。

介绍密码学原理的书中会提到这个概念,建议你查阅下相关资料。