介紹
我們有3個加密xml的方法
1、僅僅使用對稱式加密的方法加密xml
這種加密方法只使用一個密鑰,也就是說無論是加密xml還是解密xml都使用一個相同的密鑰。因為這個密鑰不會在被加密的xml中儲存,所以我們需要在加密和解密的過程中載入這個密鑰並保護它不被竊取。
2、使用對稱式加密和非對稱式加密相結合的方法來加密xml
這種方法需要一個用於加密資料的對稱金鑰和一個用於保護這個對稱金鑰的非對稱金鑰。被加密的對稱金鑰和被加密的資料一起儲存在xml文檔中。當用私人非對稱金鑰解密密鑰的時候要用公開非對稱金鑰對密鑰進行加密。
本文就將使用這種方法。想學到其他更多的方法請參看MSDN等到更多的資訊。
(譯者註:非對稱式加密演算法需要兩個密鑰:公開密鑰(publickey)和私人密鑰(privatekey)。公開密鑰與私人密鑰是一對,如果用公開金鑰組資料進行加密,只有用對應的私人密鑰才能解密;如果用私人金鑰組資料進行加密,那麼只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種演算法叫作非對稱式加密演算法。)
3、使用X.509加密xml,這種方法是用X.509作為非對稱金鑰,它由諸如VeriSign之類的第三方提供。
方法
不管xml加密是如何完成的,儲存加密資料總是用兩種方法之一。
1、加密後所有的元素都被命名為<EncryptedData>
2、加密後只有資料被替換,而元素名稱仍然是可讀的,不會發生變化。
這種微妙的變化是非常重要的。例如:
如果你的xml文檔中包括被稱為<employee>的根項目,該根項目有一個下儲存了一段詳細資料的被稱做<WrittenWarning>的子項目。如果你發送這個xml,並且想<WrittenWarning>這個元素被保護起來,那麼使用第1中方法的話<WrittenWarning>將被替換為<EncryptedData>,你不會從加密後的文檔中擷取到任何可讀的資訊。
如果使用第2種方法,那麼<WrittenWarning>元素仍然被保留,只用資料會被加密。任何得到這個文檔的人雖然不能知道該元素下的詳細資料,但仍然知道有一些事情發生在這個僱員身上。另外,<WrittenWarning>元素的所有屬性也不會被加密。
所以,如果沒有特殊需求,我們一般都用第1種方法。在.net 2.0中你可以通過修改一個Boolean值的屬性,便可以非常簡單的選擇使用哪種方法。
xml加密的例子
下面這個xml加密的例子使用的是非對稱式加密法,把xml文檔的author元素下的內容加密並把author元素用<EncryptedData>給替換掉。
XML文檔:
<?xml version="1.0" standalone="no"?> <article> <articleinfo> <title>XPath Queries on XmlDocument objects in .NET 1.1</title> <abstract> <para>This article covers the basics.</para> </abstract> <author> <honorific>Mr.</honorific> <firstname>George</firstname> <surname>James</surname> <email>gjames@doman.com</email> </author> </articleinfo> </article> |
XPath運算式為/article/articleinfo/author
被加密後的xml文檔:
<?xml version="1.0" standalone="no"?> <article> <articleinfo> <title>XPath Queries on XmlDocument objects in .NET 1.1</title> <abstract> <para>This article covers the basics.</para> <para>This article does not cover.</para> </abstract> <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#rsa-1_5" /> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <KeyName>session</KeyName> </KeyInfo> <CipherData> <CipherValue>r4f7SI1aZKSvibb…</CipherValue> </CipherData> </EncryptedKey> </KeyInfo> <CipherData> <CipherValue>sGNhKqcSovipJdOFCFKYEEMRFd…</CipherValue> </CipherData> </EncryptedData> </articleinfo> </article> |
author元素及其子項目都將被<EncryptedData>給替換掉,另外還包括其他一些元素,如密碼編譯演算法,密鑰等。
<EncryptedData>元素
仔細看看<EncryptedData>元素的樹形結構,你會發現<EncryptedData>元素下分解出了很多子項目。其中<KeyInfo>元素與xml數位簽章中的<KeyInfo>元素是相同的。
EncryptedData元素被包含在“http://www.w3.org/2001/04/xmlenc#”命名空間中。它是被加密資料的根項目。
EncryptionMethod元素指定加密資料的對稱方法。做這件事需要使用一個包含了w3 url的演算法屬性 - “http://www.w3.org/2001/04/xmlenc#aes256-cbc”,它指出資料是用AES(Rijndael)以256k的祕密金鑰加密的。
KeyInfo元素來自xml數位簽章,它儲存著對稱金鑰的資訊,除此之外該元素還能儲存更多的資訊。
KeyInfo元素下的EncryptedKey元素及其子項目包含著關於被儲存的密鑰的資訊。
KeyInfo下的EncryptionMethod元素包含的非對稱式加密方法用來加密對稱金鑰。做這件事需要把一個演算法屬性設定給w3 url。例如:“http://www.w3.org/2001/04/xmlenc#rsa-1_5”說明使用了RSA非對稱演算法來加密對稱金鑰。
KeyName元素是一個標識符,用來發現密鑰。稍後在我們編程的時候你將會發現它的重要性。
CipherData元素和CipherValue元素出現在EncryptedKey元素和EncryptedData元素下,它們包含著密碼資料。事實上密碼資料儲存在CipherValue元素下的。EncryptedKey元素下儲存的是被加密的密鑰,EncryptedData元素下的CipherValue儲存的是被加密的資料。
非對稱xml加密步驟
xml加密的過程可以概括為以下五步:
1、選擇xml文檔中的一個元素(選擇根項目的話將加密整個文檔)
2、使用一個對稱金鑰密碼編譯元素
3、使用非對稱式加密來加密上面那個對稱金鑰(使用公開密鑰)
4、建立一個EncryptedData元素,該元素下將包含被加密的資料和被加密的密鑰
5、用加密後的元素替換掉初始元素。
這些步驟的大部分都可以使用.net 2.0中的類自動完成。
非對稱xml解密步驟
xml解密的過程可以概括為以下四步:
1、在xml文檔中選擇一個EncryptedData元素
2、使用一個非對稱金鑰來解密密鑰(使用私人密鑰)
3、使用未加密的密鑰來解密資料
4、把EncryptedData元素替換成未加密的元素
這些步驟的大部分都可以使用.net 2.0中的類自動完成。
命名空間
完成xml的加密,我們需要引入三個命名空間
System.Xml - 包含操作xml的類
System.Security.Cryptography - 包含產生加密金鑰的類
System.Security.Cryptography.Xml - 包含完成加密任務的類
使用.net加密xml
本文提供了一個簡單的加密、解密xml的應用程式,下面我們一起來看一看相關的代碼。這個樣本只有一些準系統,你可以再額外加一些如選擇節點之類的功能
首先載入非對稱公開密鑰來加密金鑰
// 建立一個用於加密金鑰的非對稱金鑰 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); // 載入一個公開密鑰 XmlDocument pubKeys = new XmlDocument(); pubKeys.Load(Application.StartupPath + "\\xml.dev.keys.public"); // 使用公開祕密金鑰加密密鑰 rsa.FromXmlString(pubKeys.OuterXml); |
接下來載入xml文檔並選擇一個需要加密的節點。下面的程式碼範例了如何使用一個XPath運算式來選擇節點。如果不選擇節點,則整個xml文檔都將被加密。
// xml文檔 this.xmlEncDoc = new XmlDocument();
// 給xml文檔載入一些節點和資料(省略)
XmlElement encElement; // 如果沒有xpath則 if (xpath == string.Empty) { encElement = this.xmlEncDoc.DocumentElement; } else { XmlNamespaceManager xmlns = this.xmlCntrlr.xmlnsManager; // 通過xpath選擇出需要加密的元素 encElement = this.xmlEncDoc.SelectSingleNode(xpath, xmlns) as XmlElement; } |
使用EncryptedXml類去加密資料和密鑰
// 完成加密xml的類 EncryptedXml xmlEnc = new EncryptedXml(this.xmlEncDoc); // 增加一個“session”密鑰,使用rsa編碼 xmlEnc.AddKeyNameMapping("session", rsa); // 使用“session”密鑰來加密資料 // 這些資訊被儲存在KeyInfo元素下 EncryptedData encData = xmlEnc.Encrypt(encElement, "session"); |
用加密後的元素替換初始元素
// 用加密後的元素替換初始元素 EncryptedXml.ReplaceElement(encElement, encData, false); |
使用.net解密xml
首先載入私人非對稱金鑰來解密密鑰
// 建立一個用於解密密鑰的非對稱金鑰 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); // 載入私人密鑰 XmlDocument privKeys = new XmlDocument(); privKeys.Load(Application.StartupPath + "\\xml.dev.keys.private"); // 使用私人密鑰來解密密鑰 rsa.FromXmlString(privKeys.OuterXml); 增加一個密鑰名稱並映射到被加密的文檔中 // 增加一個密鑰名稱並映射到被加密的文檔中 EncryptedXml encXml = new EncryptedXml(xmlEncDoc); encXml.AddKeyNameMapping("session", rsa); 通過指定的密鑰來解密文檔的每一個EncryptedData元素 // 解密所有<EncryptedData>元素 encXml.DecryptDocument(); |
總結
xml加密(XML Encryption)是w3c加密xml的標準。加密後的文檔仍然是xml格式。我們使用非對稱和對稱演算法來加密xml,對稱演算法用於加密資料,非對稱演算法用於加密對稱演算法中的密鑰,加密後的資料被儲存在EncryptedData元素下。EncryptedData元素包含著一些列用於描述演算法的子項目,同時也包含著密鑰資訊。