介紹
我們有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>[email protected]</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元素包含著一些列用於描述算法的子元素,同時也包含著密鑰信息。