利用XML Signature, 消息的完整性(Integrity)得到了保證。回顧之前提到的安全的三個基本概念: Integrity, Confidentiality, Authentication, 現在該考慮消息的機密性的問題。
雖然簽名可以保證消息在傳送的途中沒有被篡改,但是並不能避免它被偷取。如果消息沒有經過加密,那麼某個敏感的信息就會被泄漏。
與XML-Signature類似,結合了XML技術和傳統加密技術而產生的XML-Encryption,也並不僅僅是加密XML文件那麼簡單,它提供了以下的功能:
- 加密整個XML文件。
- 加密XML文件中的某個元素。
- 加密XML文件中某個元素的內容。
- 加密非XML格式的資源。(例如一張JPEG圖片)。
- 加密已經過加密的內容。
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中顯然是不安全的。
此時有以下幾種方法:
- 不使用KeyInfo元素,假定消息交換已經約定好了加密使用的密鑰。
- 在KeyInfo中指定一個標識(Identity),假定消息接受方已經擁有了解密所需的密鑰,通過這個標識,消息接受方接可以定位到此次解密所需要的密鑰。
- 使用消息接受方的公鑰加密此次加密消息所使用的對稱密鑰,消息接受方利用自己唯一擁有的私鑰解密出加密消息使用的密鑰。
- 通過key agreement protocol獲得密鑰(較少使用)。
基於以上幾種方法,下面對KeyInfo元素做具體介紹:
KeyName: 方法2中的一種形式,通過指定一個標識來獲得解密所需的密鑰。
RetrievalMethod: 方法2中的另一種形式,通過一個URI指向解密所需的密鑰, 比如指向信息中另一段被加密的內容,而那段內容可以方便的被解密。
EncryptedKey: 爲了使用第3種方法,XML Encryption爲KeyInfo加入的擴展元素。通過非對稱密鑰技術來傳遞對稱密鑰,綜合了兩種的優點,前提是消息加密方需擁有消息接受方的公鑰。下面是使用該方法的一個例子。
AgreementMethod: 該元素使用key agreement protocol來獲得密鑰,極少使用故不做介紹。
示例1:
<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元素可以在密鑰中引用到使用該密鑰的不同地方,避免重複,如示例2。
示例2:
<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中也有類似的實現,如示例3:
示例3:
<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.根據以上信息將密文解密獲得原始信息。