如何使用C#加密解密XML文档

如何使用C#加密解密XML文档

 

      .NETFramework提供了几种类,可用于对 XML数据进行加密和解密,以及创建和验证 XML数字签名。这些类提供了维护 XML数据的保密性和完整性的方法。在这里,我们只涉及如何使用.NETFramework本身提供了的EncryptedXml类进行加密和解密。该类提供了一些方法,能够让用户使用不同的算法进行加密和解密XML。

      要使用EncryptedXml类进行加密和解密,我们需要搞清楚两个主题。

1.    加密算法的选取。

2.    如何进行加密。

      涉及到加密算法,一般分为两种类型的算法,对称加密算法(SymmetricAlgorithm)和非对称加密算法(AsymmetricAlgorithm)。两种算法的区别在于,使用对称加密算法进行加密和解密,加密过程和解密过程都是使用同一个密钥;对于非对称加密和解密,则是使用一个相互匹配密钥对----公钥和私钥进行加解密。【顺便简单的提及一下非对称加密方式和原理。对于这种类型的加密,加密密钥和解密密钥是相对的说法,如果用加密密钥加密那么只有解密密钥才能恢复,如果用解密密钥加密则只有加密密钥能解密,所以它们被称为密钥对,其中的一个可以在网络上发送、公布,叫做公钥,而另一个则只有密钥对的所有人才持有,叫做私钥,非对称公开密钥系统又叫做公钥系统。非对称加密算法的基本原理是,如果发信方想发送只有收信方才能解读的加密信息,发信方必须首先知道收信方的公钥,然后利用收信方的公钥来加密原文;收信方收到加密密文后,使用自己的私钥才能解密密文。显然,采用不对称加密算法,收发信双方在通信之前,收信方必须将自己早已随机生成的公钥送给发信方,而自己保留私钥。】另外,这两种加密在效率上有比较大的区别,前者效率高,后者效率要相对低一些。所以,加密大量数据,一般都是采用对称加密算法将数据进行加密,为了使加密更加安全,再使用非对称加密算法将加密数据的对称加密密钥进行加密,这样,在进行网络传输时,即保证了加密数据的效率,又保证了加密数据的安全性,当然,在没有将加密的数据进行网络传输时,就没有必要使用非对称加密了,普通的对称加密就可以满足需求。(大家可以仔细Google一下。)

       对于这两种加密,常见对称加密算法有DES, AES(又称为Rijndael,其密钥长度分128,192,256位这三种), TripleDES等;非对称加密算法常见的有RSA算法。这几种加密算法对应的类分别是:DESCryptoServiceProviderRijndaelManagedTripleDESCryptoServiceProvider以及RSACryptoServiceProvider。前有三种都从SymmetricAlgorithm继承过来,最后一种从AsymmetricAlgorithm继承过来。


好了,基本上关于加密解密,我们已以有一个大致的了解,那么,下面详细的描述一下如何进行加密和解密。

在下面的描述中,我参考了以下文档:

XMLEncryption Syntax and ProcessingW3C XML加解密标准文档

XML加密和数字签名该主题下含有XML各种类型的加解密

假定现在有如下XML文档(test.xml),我们要对其进行加密/解密:

[xhtml] view plain copy
  1. <root>  
  2.   <creditcard>  
  3.     <number>19834209</number>  
  4.     <expiry>02/02/2002</expiry>  
  5.   </creditcard>  
  6. </root>  

加密的大致流程如下:

1.    通过从磁盘加载 XML文件创建 XmlDocument对象。XmlDocument对象包含要加密的 XML 元素。

2.    在 XmlDocument对象中找到指定的元素,然后创建一个新的XmlElement 对象来表示要加密的元素。

3.    创建 EncryptedXml类的新实例,并使用它通过指定的加密算法对XmlElement进行加密。

4.    构造一个 EncryptedData对象,用XML加密元素的 URL 标识符、EncryptedKey信息等填充它,并将加密数据填充到该结构体里面去。(很重要,很繁琐的步骤)

5.    用 EncryptedData元素替换原始 XmlDocument对象中的元素。

我们直接拿test.xml来加密,要加密的元素是<number>,加密粒度是该结点,加密数据采用最简单的DES加密,加密后的XML文档变为:

[xhtml] view plain copy
  1. <root>  
  2.   <creditcard>  
  3.     <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#">  
  4.       <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#des-cbc" />  
  5.       <CipherData>  
  6.         <CipherValue>3oIDgOJMW0/Ev3duGiCvsVdDgPzP7X0399xwVKMR8MQUGO1AMTIlFA==</CipherValue>  
  7.       </CipherData>  
  8.     </EncryptedData>  
  9.     <expiry>02/02/2002</expiry>  
  10.   </creditcard>  
  11. </root>  

从该加密后的XML里面可以看得出来,<EncryptedData>这个节点里面的内容为加密后的核心内容,但这里面真正被加密的内容在哪?很明显,<CipherValue>3oIDgOJMW0/Ev3duGiCvsVdDgPzP7X0399xwVKMR8MQUGO1AMTIlFA==这一长串就是加密后的真正数据。那其它部分都是些什么内容?这里,我们需要熟悉一下W3C关于加密的标准。可参见XMLEncryption Syntax and Processing文档。


从加密后的XML里面可以看出,<EncryptedData>节点包含了被加密后的数据和其它信息,W3C为其定义的标准结构如下:

(其中,“?”表示出现0次或1次,“+”表示出现1次或多次,“*”表示0次或多次,空元素标签表示该元素的内容为空)

 

[xhtml] view plain copy
  1. <EncryptedData Id? Type? MimeType? Encoding?>  
  2.   <EncryptionMethod/>?  
  3.   <ds:KeyInfo>  
  4.     <EncryptedKey>?  
  5.     <AgreementMethod>?  
  6.     <ds:KeyName>?  
  7.     <ds:RetrievalMethod>?  
  8.     <ds:*>?  
  9.   </ds:KeyInfo>?  
  10.   <CipherData>  
  11.     <CipherValue>?  
  12.     <CipherReference URI?>?  
  13.   </CipherData>  
  14.   <EncryptionProperties>?  
  15. </EncryptedData>  

 

 

其中:

1.    <EncryptionMethod>用于描述加密方式。一般情况下,需要设置该项。

2.    <ds:KeyInfo>用于描述用于加密数据的key。一般情况下,需要设置该项的<KeyName>节点。

3.    <EncryptedKey>用于描述将加密数据的key①进行加密的新key②的信息。有点绕,实际上,它出现于这样的情形:当我们使用对称加密key(如:DES加密)对数据进行加密,为了加密更加安全,然后采用另外一种高级加密方式(如:RSA加密),对这个key再进行一次加密,并将这个key加密后的生成的加密数据保存到<EncryptedKey>里面的<CipherData>节点下面。解密时,需要通过给出key②,先将原始加密数据的key①解密出来,再将原始数据进行解密。要注意一点,<EncryptedKey>的数据结构实际上和<EncryptedData>的数据结构是类似的。给出一个简单的例子,如:

[c-sharp] view plain copy
  1. <EncryptedKey Id="EK" xmlns="http://www.w3.org/2001/04/xmlenc#">  
  2.   <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />  
  3.   <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">  
  4.     <ds:KeyName>John Smith</ds:KeyName>  
  5.   </ds:KeyInfo>  
  6.   <CipherData>  
  7.     <CipherValue>xyzabc</CipherValue>  
  8.   </CipherData>  
  9.   <ReferenceList>  
  10.     <DataReference URI="#ED" />  
  11.   </ReferenceList>  
  12.   <CarriedKeyName>Sally Doe</CarriedKeyName>  
  13. </EncryptedKey>  
 

这里面<CipherValue>xyzabc</CipherValue>中的数据实际上就是被加密后的key.

MSDN上所给出的DEMO称这种方式为非对称加密方式,但我认为有些不妥,因为加密真正数据的部分并没有采用非对称加密方式,而只是将key①使用了非对称加密。

4.    元素<CipherData>代表加密数据的结构,其中的<CipherValue>代表真正加密后的数据。

 


对于以上所有结构,在.NET Framework的类里面都有对应的类。

EncryptedData Class

EncryptionMethod Class

KeyInfo Class

EncryptedKey Class

CipherData Class

CipherReference Class

KeyInfoName Class

……

(个人感觉,这些类实在是太多了,有点抽象过度的嫌疑。)

另外,我们需要了解一下加密粒度(Encryption Granularity)。加密粒度分两种,一是加密节点内部的数据,另一个加密整个节点。比如,我们可以选择只加密<number>的内容19834209,当然也可以选择加密<number>整个结点。

实际上,通过上面的内容可以看出,加密XML最核心的东西实际上只有两个部分,第一是将原始数据进行加密,第二是构建<EncryptedData>节点内的数据。

 

OK,整个加密的流程以及相关的背景知识介绍得差不多了。下面通过封装一个加解密的类(GTXXmlCrypt)来说明如何使用EncryptedXml进行加解密。

首先,需要描述我们所使用的EncryptedXml类里面几个重要的方法,这几个方法也是在这个封装类里面用到的,简单描述一下,详细请见MSDN

1. publicbyte[]EncryptData(XmlElementinputElement,SymmetricAlgorithmsymmetricAlgorithm,boolcontent);

a)    通过给定的对称加密算法,对指定的节点进行加密,content指明是否是加密整个节点还是只加密节点内容。

b)    在该类中,用于加密节点的方法只能通过称加密算法,而不能够通过非对称加密节点,可能他们认为使用非对称加密的实际含义是:先通过对称加密将数据进行加密,再用非对称加密将前者(对称加密的key)进行加密,这种方式才叫非对称加密。

2. publicbyte[]DecryptData(EncryptedDataencryptedData,SymmetricAlgorithmsymmetricAlgorithm);

a)    通过给定的对称解密算法(加密和解密的key是一样的),将数据进行解密,同样,只能使用对称加密方式。

3. publicvoidDecryptDocument();

a)    解密整个文档,但它使用的前提是:在被加密后的文档中,<EncryptedData>节点必须含有<KeyInfo>,而且其中的<KeyName>必须有值。可以通过将要封装的类实验。

4. publicstaticvoid ReplaceElement(XmlElementinputElement,EncryptedDataencryptedData,boolcontent);

a)    当加密完后,需要用EncryptedData来替换加密的节点。

5. publicstaticbyte[] DecryptKey(byte[]keyData, SymmetricAlgorithmsymmetricAlgorithm);

a)    该方法通过对称加密算法解密“加密原数据的密钥”。

6. publicstaticbyte[] DecryptKey(byte[]keyData, RSArsa, bool useOAEP);

a)    该方法通过非对称加密算法解密“加密原数据的密钥”。

 

我们需要封装的GTXXmlCrypt类有以下需求:

1.    能够加载一个xml文件进行加解密;

2.    能够某个XmlDocument进行加解密;

3.    能够对单个指定的节点进行加解密;

4.    能够指定各种加解密的方式,如指定加密方式为DES,AES,RSA等;

 

该类的框架如下:(请原谅我只给出了一个代码的架子,也没有用类图的形式表示出来,因为我会将所有代码全部贴上来。)

 

[c-sharp] view plain copy
  1. namespace GTXUtility.Security.Crypt  
  2. {  
  3.     public class GTXXmlCrypt  
  4.     {  
  5.         // 定义对称加密类型,对于非对称加密类型,我没有给出重新定义一个结构体,  
  6.         // 原因是因为EncryptedXml类对非对称加密只支持RSA,而且RSA也不是用来加密数据的,而是用来加密key的。  
  7.         public enum SymmetricAlgTypes  
  8.         {  
  9.             DES = 1,  
  10.             AES128, // Rijndael 128  
  11.             AES192, // Rijndael 192  
  12.             AES256, // Rijndael 256  
  13.             TripleDES,  
  14.         }  
  15.         // 该类通过指定的对称加密类型,创建对应的对称加密key,  
  16.         // 实际上,对于创建加密key,完全可以另外写个类,进行操作,而不应该放在该类里面。  
  17.         public static SymmetricAlgorithm CreateSymmetricAlgorithm(SymmetricAlgTypes salType);  
  18.         // 该类用于创建RSA key,  
  19.         // 实际上,对于创建加密key,完全可以另外写个类,进行操作,而不应该放在该类里面。  
  20.         public static RSA CreateRSAAlgorithm(String containerName);  
  21.           
  22.         // 加密指定的文件,该函数内部会调用EncryptXmlDoc函数。  
  23.         public static bool EncryptXmlFile(  
  24.             String filePath,        // 指定需要加密的文件  
  25.             String elementName,     // 需要指定加密的元素  
  26.             bool bContent,          // 是否只加密元素的内容?  
  27.             object key,             // 加密密钥,可以是对称的,也可以是非对称的  
  28.             String keyName);        // 指定加密密钥的名称(可选)  
  29.         // 加密指定的XmlDocument对象,该函数内部会循环调用EncryptXmlNode函数  
  30.         //(该函数分为对称密钥版和非对称密钥版)加密XmlDocument内部所有符合要求的节点。  
  31.         public static bool EncryptXmlDoc(  
  32.             XmlDocument xmlDoc,     // 指定需要加密的XmlDocument对象  
  33.             String elementName,     // 需要指定加密的元素   
  34.             bool bContent,          // 是否只加密元素的内容?  
  35.             object key,             // 加密密钥,可以是对称的,也可以是非对称的  
  36.             String keyName);        // 指定加密密钥的名称(可选)  
  37.         // (核心功能)加密指定的节点(对称加密方式)  
  38.         public static bool EncryptXmlNode(  
  39.             XmlElement elementToEncrypt,    // 指定需要加密的XmlElement对象(节点)  
  40.             bool bContent,                  // 是否只加密元素的内容?  
  41.             SymmetricAlgorithm salgKey,     // 对称加密密钥  
  42.             String keyName);                // 指定加密密钥的名称(可选)  
  43.         // (核心功能)加密指定的节点(非对称加密方式)  
  44.         public static bool EncryptXmlNode(  
  45.             XmlElement elementToEncrypt,    // 指定需要加密的XmlElement对象(节点)  
  46.             bool bContent,                  // 是否只加密元素的内容?  
  47.             RSA rsaKey,                     // 对称加密密钥,用于加密sessionKey到<EncryptedKey>节点中去  
  48.             String keyName,                 // 指定加密密钥的名称(可选)  
  49.             SymmetricAlgorithm sessionKey); // 用于加密原始数据的对称密钥(注:加密数据只能用对称加密)  
  50.         // 解密指定的文件,该函数内部会调用DecryptXmlDoc函数。  
  51.         public static bool DecryptXmlFile(String filePath, object key, String keyName);  
  52.         // 解密指定的XmlDocument对象,该函数内部会循环调用DecryptXmlNode函数  
  53.         public static bool DecryptXmlDoc(XmlDocument xmlDoc, object key, String keyName);  
  54.         // (核心功能)解密指定的节点(对称加密方式和非对称加密方式统统放在一个函数内)  
  55.         public static bool DecryptXmlNode(XmlElement encryptedElement, SymmetricAlgorithm salgKey);  
  56.           
  57.         // 该函数用于创建<EncryptionMethod>节点对象  
  58.         private static EncryptionMethod CreateEncryptionMethod(object keyAlg, bool isKeyWrapAlgUri, bool isOaep);  
  59.         // 该类用于解密使用RSA加密时,所使用到的sessionkey,内部调用GenerateSyAlgKey函数  
  60.         private static SymmetricAlgorithm DecryptKey(XmlDocument xmlDoc, object decryptKey);  
  61.         // 该类用于解密使用RSA加密时,所使用到的sessionkey  
  62.         private static SymmetricAlgorithm GenerateSyAlgKey(byte[] decryptedKeyData, EncryptionMethod encMethod);  
  63.     }  
  64. }  

该类基本上比较简单,我们只重点分析一下加密的核心功能。

[c-sharp] view plain copy
  1. public static bool EncryptXmlNode(  
  2.     XmlElement elementToEncrypt,   
  3.     bool bContent,   
  4.     SymmetricAlgorithm salgKey,   
  5.     String keyName)  
  6. {  
  7.     if (null == elementToEncrypt || null == salgKey)  
  8.     {  
  9.         return false;  
  10.     }  
  11.     try  
  12.     {  
  13.         // 1. Create a new instance of the EncryptedXml class and use it    
  14.         // to encrypt the XmlElement with the symmetric key.  
  15.         EncryptedXml eXml = new EncryptedXml();  
  16.         byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, salgKey, bContent);  
  17.         // 2. Construct an EncryptedData object and populate it   
  18.         // with the desired encryption information.  
  19.         EncryptedData edElement = new EncryptedData();  
  20.         edElement.Type = EncryptedXml.XmlEncElementUrl;  
  21.         // 3. Create an EncryptionMethod element so that the receiver   
  22.         // knows which algorithm to use for decryption.  
  23.         edElement.EncryptionMethod = CreateEncryptionMethod(salgKey, false, false);  
  24.         // 4. Set the KeyInfo element to specify the name of the key.  
  25.         if (null != keyName && !keyName.Equals(String.Empty))  
  26.         {  
  27.             // Create a new KeyInfo element.  
  28.             edElement.KeyInfo = new KeyInfo();  
  29.             // Create a new KeyInfoName element.  
  30.             KeyInfoName kin = new KeyInfoName();  
  31.             // Specify a name for the key.  
  32.             kin.Value = keyName;  
  33.             // Add the KeyInfoName element.  
  34.             edElement.KeyInfo.AddClause(kin);  
  35.         }  
  36.         // 5. Add the encrypted element data to the EncryptedData object.  
  37.         edElement.CipherData.CipherValue = encryptedElement;  
  38.         // 6. Replace the element from the original XmlDocument  
  39.         // object with the EncryptedData element.  
  40.         EncryptedXml.ReplaceElement(elementToEncrypt, edElement, bContent);  
  41.         return true;   
  42.     }  
  43.     catch (System.Exception ex)  
  44.     {  
  45.     }  
  46.     return false;  
  47. }  
 

 

加密某个节点分以下步骤:

<!--[if !supportLists]-->1.<!--[endif]-->创建 EncryptedXml类的新实例,并使用它通过对称密钥对 XmlElement进行加密。EncryptData方法将加密的元素作为加密字节的数组返回。

<!--[if !supportLists]-->2.<!--[endif]-->构造一个 EncryptedData对象,然后用 XML加密元素的 URL 标识符填充它。此 URL标识符使解密方知道 XML 包含一个加密元素。可以使用 XmlEncElementUrl字段指定 URL标识符。

<!--[if !supportLists]-->3.<!--[endif]-->创建 EncryptionMethod对象,该对象被初始化为用来生成密钥的加密算法的URL标识符。将 EncryptionMethod对象传递给 EncryptionMethod属性。

<!--[if !supportLists]-->4.<!--[endif]-->如果用户给加密数据的key设置了一个名称,那就创建一个KeyInfo的对象,并通过KeyInfoName为其指定一个名称。

<!--[if !supportLists]-->5.<!--[endif]-->将加密的元素数据添加到 EncryptedData对象中。

<!--[if !supportLists]-->6.<!--[endif]-->用EncryptedData元素替换原始 XmlDocument对象中的元素。

 

使用RSA加密的整体流程和这个类似,只不过多了一步加密sessionkey(加密原始数据的key)的过程。在这里我就不再赘述了,请直接看源代码。

以下是解密的代码:

[c-sharp] view plain copy
  1. public static bool DecryptXmlDoc(XmlDocument xmlDoc, object key, String keyName)  
  2. {  
  3.     try  
  4.     {  
  5.         // First, we try to decrypt xml document with EncryptedXml.DecryptDocument() method,   
  6.         // this method decrypts all <EncryptedData> elements of the XML document, but its precondition  
  7.         // is that the <EncryptedData> elements has been specified <KeyInfo>'s <KeyName>, if this element  
  8.         // hasn't been specified, it will failed and throw a CryptographicException exception.  
  9.         // Second, if we hasn't specified key name, we can only decrypt the document with SymmetricAlgorithm  
  10.         // key, this is restricted to the API of EncryptedXml class.  
  11.         if (null != keyName && !keyName.Equals(String.Empty))  
  12.         {  
  13.             // Create a new EncryptedXml object.  
  14.             EncryptedXml exml = new EncryptedXml(xmlDoc);  
  15.             // Add a key-name mapping.  
  16.             // This method can only decrypt documents that present the specified key name.  
  17.             exml.AddKeyNameMapping(keyName, key);  
  18.             // Decrypt the element.  
  19.             exml.DecryptDocument();  
  20.             return true;  
  21.         }  
  22.         else  
  23.         {  
  24.             SymmetricAlgorithm salgKey = null;  
  25.             RSA rsaKey = null;  
  26.             if (key is SymmetricAlgorithm)  
  27.             {  
  28.                 salgKey = key as SymmetricAlgorithm;  
  29.             }  
  30.             else if (key is RSA)  
  31.             {  
  32.                 rsaKey = key as RSA;  
  33.                 salgKey = DecryptKey(xmlDoc, key);  
  34.             }  
  35.             else  
  36.             {  
  37.                 return false;  
  38.             }  
  39.             XmlNodeList nodeList = xmlDoc.GetElementsByTagName("EncryptedData");  
  40.             int nCount = nodeList.Count;  
  41.             for (int ix = 0; ix < nCount; ++ix)  
  42.             {  
  43.                 XmlElement encryptedElement = nodeList[0] as XmlElement;  
  44.                 if (null != salgKey)  
  45.                 {  
  46.                     if (!DecryptXmlNode(encryptedElement, salgKey))  
  47.                     {  
  48.                         return false;  
  49.                     }  
  50.                 }  
  51.             }  
  52.             return true;  
  53.         }  
  54.     }  
  55.     catch (System.Exception ex)  
  56.     {  
  57.     }  
  58.     return false;  

解密分两步:

<!--[if !supportLists]-->1.    <!--[endif]-->如果给出了keyName和解密密钥,那么直接使用EncryptedXml的DecryptDocument方法。

<!--[if !supportLists]-->2.    <!--[endif]-->否则,我们就需要一个节点一个节点的解密了。对于非对称的解密,一般直接使用DecryptDocument方法就可以了。

 


整个代码如下:

GTXXmlCrypt代码:

[c-sharp] view plain copy
  1. /*! 
  2.  * @file GTXXmlCrypt.cs 
  3.  *  
  4.  * @brief This file implements the class of GTXXmlCrypt. 
  5.  *        This class is used to crypt or decrypt xml file. 
  6.  *  
  7.  * Copyright (C) 2011, GTX. 
  8.  *  
  9.  * @author Liu Lin 
  10.  * @date 2011/6/19 
  11.  */  
  12. using System;  
  13. using System.IO;  
  14. using System.Security.AccessControl;  
  15. using System.Security.Cryptography;  
  16. using System.Security.Cryptography.Xml;  
  17. using System.Security.Principal;  
  18. using System.Xml;  
  19. namespace GTXUtility.Security.Crypt  
  20. {  
  21.     /// <summary>  
  22.     /// This class is used to encrypt xml file with Symmetric Encryption Algorithm (such as   
  23.     /// DES, AES, TripleDES and so on) and Asymmetric Encryption Algorithm (such as RSA).  
  24.     /// </summary>  
  25.     /// <remarks>  
  26.     /// Expressed in shorthand form, the EncryptedData element has the following structure:  
  27.     /// (where "?" denotes zero or one occurrence;   
  28.     /// "+" denotes one or more occurrences;   
  29.     /// "*" denotes zero or more occurrences;   
  30.     /// and the empty element tag means the element must be empty )  
  31.     ///   <EncryptedData Id? Type? MimeType? Encoding?>  
  32.     ///     <EncryptionMethod/>?  
  33.     ///     <ds:KeyInfo>  
  34.     ///       <EncryptedKey>?  
  35.     ///       <AgreementMethod>?  
  36.     ///       <ds:KeyName>?  
  37.     ///       <ds:RetrievalMethod>?  
  38.     ///       <ds:*>?  
  39.     ///     </ds:KeyInfo>?  
  40.     ///     <CipherData>  
  41.     ///       <CipherValue>?  
  42.     ///       <CipherReference URI?>?  
  43.     ///     </CipherData>  
  44.     ///     <EncryptionProperties>?  
  45.     ///   </EncryptedData>   
  46.     /// The <EncryptedKey> is the same with the <EncryptedData>.  
  47.     /// To get some more informations, please attach the following references.  
  48.     /// http://www.w3.org/TR/xmlenc-core/  
  49.     /// http://msdn.microsoft.com/zh-cn/library/system.security.cryptography.xml.encryptedxml.aspx  
  50.     /// </remarks>  
  51.     public class GTXXmlCrypt  
  52.     {  
  53.         /// <summary>  
  54.         /// Defines Symmetric Encryption Algorithm types.  
  55.         /// </summary>  
  56.         public enum SymmetricAlgTypes  
  57.         {  
  58.             DES = 1,  
  59.             AES128, // Rijndael 128  
  60.             AES192, // Rijndael 192  
  61.             AES256, // Rijndael 256  
  62.             TripleDES,  
  63.         }  
  64.         /// <summary>  
  65.         /// Create a Symmetric Encryption Algorithm object.  
  66.         /// </summary>  
  67.         /// <param name="salType">Specified Symmetric Encryption Algorithm type.</param>  
  68.         /// <returns>If create success, returns the Symmetric Encryption Algorithm object.  
  69.         /// Otherwise, return null object.</returns>  
  70.         public static SymmetricAlgorithm CreateSymmetricAlgorithm(SymmetricAlgTypes salType)  
  71.         {  
  72.             SymmetricAlgorithm symAlg = null;  
  73.             switch (salType)  
  74.             {  
  75.                 case SymmetricAlgTypes.DES:  
  76.                     symAlg = SymmetricAlgorithm.Create("DES");  
  77.                     break;  
  78.                 case SymmetricAlgTypes.AES128:  
  79.                     symAlg = SymmetricAlgorithm.Create("Rijndael");  
  80.                     symAlg.KeySize = 128;  
  81.                     break;  
  82.                 case SymmetricAlgTypes.AES192:  
  83.                     symAlg = SymmetricAlgorithm.Create("Rijndael");  
  84.                     symAlg.KeySize = 192;  
  85.                     break;  
  86.                 case SymmetricAlgTypes.AES256:  
  87.                     symAlg = SymmetricAlgorithm.Create("Rijndael");  
  88.                     symAlg.KeySize = 256;  
  89.                     break;  
  90.                 case SymmetricAlgTypes.TripleDES:  
  91.                     symAlg = SymmetricAlgorithm.Create("TripleDES");  
  92.                     break;  
  93.                 default:  
  94.                     break;  
  95.             }  
  96.             return symAlg;  
  97.         }  
  98.         /// <summary>  
  99.         /// This method has two use.  
  100.         /// First, create a RSA encryption algorithm object when first use it, it'll   
  101.         /// stroe the RSA key into key container which specified by the paramter.  
  102.         /// Second, this method can get the RSA key from container when use for second time.  
  103.         /// The container name must be the same with the first.  
  104.         /// </summary>  
  105.         /// <param name="containerName">The key container name.</param>  
  106.         /// <returns>Returns the instance of RSA.</returns>  
  107.         /// <remarks>  
  108.         /// Microsoft recommends to store asymmetric keys in a key container.   
  109.         /// http://msdn.microsoft.com/zh-cn/library/tswxhw92(VS.80).aspx  
  110.         /// </remarks>  
  111.         public static RSA CreateRSAAlgorithm(String containerName)  
  112.         {  
  113.             RSACryptoServiceProvider rsaKey = null;  
  114.             try  
  115.             {  
  116.                 // Create a new CspParameters object to specify a key container.  
  117.                 CspParameters cspParams = new CspParameters();  
  118.                 cspParams.KeyContainerName = containerName;  
  119.                 cspParams.Flags = CspProviderFlags.UseMachineKeyStore;  
  120.                 // Add the key's access privilege  
  121.                 CryptoKeySecurity keySecurity = new CryptoKeySecurity();  
  122.                 SecurityIdentifier si = new SecurityIdentifier(WellKnownSidType.LocalSid/*WorldSid*/, null);  
  123.                 keySecurity.AddAccessRule(new CryptoKeyAccessRule(si, CryptoKeyRights.FullControl, AccessControlType.Allow));  
  124.                 cspParams.CryptoKeySecurity = keySecurity;  
  125.                 // Create a new RSA key and save it in the container. This key will encrypt  
  126.                 // a symmetric key, which will then be encrypted in the XML document.  
  127.                 rsaKey = new RSACryptoServiceProvider(cspParams);  
  128.             }  
  129.             catch (System.Exception ex)  
  130.             {  
  131.             }  
  132.             return rsaKey;  
  133.         }  
  134.         /// <summary>  
  135.         /// Encrypt a xml file's elements by specified key.  
  136.         /// </summary>  
  137.         /// <param name="filePath">The path of xml file which needs to be encrypted.</param>  
  138.         /// <param name="elementName">The element (node) in xml file which needs to be encrypted.</param>  
  139.         /// <param name="bContent">Whether to encrypt the element content or not. true to   
  140.         /// encrypt only the contents of the element; false to encrypt the entire element.</param>  
  141.         /// <param name="key">The specified encryption key.</param>  
  142.         /// <param name="keyName">The key name which used to display the <KeyInfo> in encrypted xml.  
  143.         /// It can be empty or null.</param>  
  144.         /// <returns>If encrypt success, return true, otherwise, return false.</returns>  
  145.         /// <remarks>After encryption success, it'll save the new data into xml file.</remarks>  
  146.         public static bool EncryptXmlFile(  
  147.             String filePath,   
  148.             String elementName,   
  149.             bool bContent,  
  150.             object key,   
  151.             String keyName)  
  152.         {  
  153.             if (File.Exists(filePath) && Path.GetExtension(filePath).ToLower().Equals(".xml") &&   
  154.                 null != elementName && !elementName.Equals(String.Empty) &&  
  155.                 null != key)  
  156.             {  
  157.                 XmlDocument xmlDoc = new XmlDocument();  
  158.                 xmlDoc.PreserveWhitespace = true;  
  159.                 xmlDoc.Load(filePath);  
  160.                 if (EncryptXmlDoc(xmlDoc, elementName, bContent, key, keyName))  
  161.                 {  
  162.                     xmlDoc.Save(filePath);  
  163.                     return true;  
  164.                 }  
  165.                 return false;  
  166.             }  
  167.             return false;  
  168.         }  
  169.         /// <summary>  
  170.         /// Encrypt a xml document's elements by specified key.  
  171.         /// </summary>  
  172.         /// <param name="xmlDoc">The XmlDocument object which needs to be encrypted.</param>  
  173.         /// <param name="elementName">The element (node) in xml file which needs to be encrypted.</param>  
  174.         /// <param name="bContent">Whether to encrypt the element content or not. true to   
  175.         /// encrypt only the contents of the element; false to encrypt the entire element.</param>  
  176.         /// <param name="key">The specified encryption key.</param>  
  177.         /// <param name="keyName">The key name which used to display the <KeyInfo> in encrypted xml.  
  178.         /// It can be empty or null.</param>  
  179.         /// <returns>If encrypt success, return true, otherwise, return false.</returns>  
  180.         public static bool EncryptXmlDoc(  
  181.             XmlDocument xmlDoc,  
  182.             String elementName,  
  183.             bool bContent,  
  184.             object key,  
  185.             String keyName)  
  186.         {  
  187.             SymmetricAlgorithm salgKey = null;  
  188.             RSA rsaKey = null;  
  189.             SymmetricAlgorithm sessionKey = null;  
  190.             // If currnet key is SymmetricAlgorithm, we'll use this key to encrypt elemnet.  
  191.             // Else if currnet key is RSA, we need to create a session key to encrypt elemnet,   
  192.             // and the RSA key is used to encrypt session key. Please pay more attention.  
  193.             if (key is SymmetricAlgorithm)  
  194.             {  
  195.                 salgKey = key as SymmetricAlgorithm;  
  196.             }  
  197.             else if (key is RSA)  
  198.             {  
  199.                 rsaKey = key as RSA;  
  200.                 sessionKey = CreateSymmetricAlgorithm(SymmetricAlgTypes.DES/*AES256*/);  
  201.             }  
  202.             else  
  203.             {  
  204.                 return false;  
  205.             }  
  206.             try  
  207.             {  
  208.                 XmlNodeList nodeList = xmlDoc.GetElementsByTagName(elementName);  
  209.                 int nCount = nodeList.Count;  
  210.                 if (0 == nCount)  
  211.                 {  
  212.                     return false;  
  213.                 }  
  214.                 for (int ix = 0; ix < nCount; ++ix)  
  215.                 {  
  216.                     // Please pay more attention about the follows:  
  217.                     // If we want to encrypt a node (XmlElement) in node list, the node will be delete  
  218.                     // after we encrypt it and the count will be decremented, as a result, each time   
  219.                     // we need to encrypt nodeList[0].  
  220.                     // But if we want to encrypt a node's content in node list, the node will NOT be delete  
  221.                     // after we encrypt it and the count will NOT be decremented, as a result, each time   
  222.                     // we need to encrypt nodeList[ix].  
  223.                     XmlElement elementToEncrypt = bContent ? (nodeList[ix] as XmlElement) : (nodeList[0] as XmlElement);  
  224.                     if (null != salgKey)  
  225.                     {  
  226.                         if (!EncryptXmlNode(elementToEncrypt, bContent, salgKey, keyName))  
  227.                         {  
  228.                             return false;  
  229.                         }  
  230.                     }  
  231.                     else if (null != rsaKey)  
  232.                     {  
  233.                         if (!EncryptXmlNode(elementToEncrypt, bContent, rsaKey, keyName, sessionKey))  
  234.                         {  
  235.                             return false;  
  236.                         }  
  237.                     }  
  238.                 }  
  239.                 return true;  
  240.             }  
  241.             catch (System.Exception ex)  
  242.             {  
  243.             }  
  244.             finally  
  245.             {  
  246.                 // Clear session key.  
  247.                 if (null != sessionKey)  
  248.                 {  
  249.                     sessionKey.Clear();  
  250.                 }  
  251.             }  
  252.             return false;  
  253.         }  
  254.         /// <summary>  
  255.         /// Encrypt a xml element (node) by specified Symmetric Algorithm key.  
  256.         /// </summary>  
  257.         /// <param name="elementToEncrypt">The element which needs to be encrypted.</param>  
  258.         /// <param name="bContent">Whether to encrypt the element content or not. true to   
  259.         /// encrypt only the contents of the element; false to encrypt the entire element.</param>  
  260.         /// <param name="salgKey">Specified Symmetric Algorithm key.</param>  
  261.         /// <param name="keyName">The key name which used to display the <KeyInfo> in encrypted xml.  
  262.         /// It can be empty or null.</param>  
  263.         /// <returns>If encrypt success, return true, otherwise, return false.</returns>  
  264.         public static bool EncryptXmlNode(  
  265.             XmlElement elementToEncrypt,   
  266.             bool bContent,   
  267.             SymmetricAlgorithm salgKey,   
  268.             String keyName)  
  269.         {  
  270.             if (null == elementToEncrypt || null == salgKey)  
  271.             {  
  272.                 return false;  
  273.             }  
  274.             try  
  275.             {  
  276.                 // 1. Create a new instance of the EncryptedXml class and use it    
  277.                 // to encrypt the XmlElement with the symmetric key.  
  278.                 EncryptedXml eXml = new EncryptedXml();  
  279.                 byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, salgKey, bContent);  
  280.                 // 2. Construct an EncryptedData object and populate it   
  281.                 // with the desired encryption information.  
  282.                 EncryptedData edElement = new EncryptedData();  
  283.                 edElement.Type = EncryptedXml.XmlEncElementUrl;  
  284.                 // 3. Create an EncryptionMethod element so that the receiver   
  285.                 // knows which algorithm to use for decryption.  
  286.                 edElement.EncryptionMethod = CreateEncryptionMethod(salgKey, false, false);  
  287.                 // 4. Set the KeyInfo element to specify the name of the key.  
  288.                 if (null != keyName && !keyName.Equals(String.Empty))  
  289.                 {  
  290.                     // Create a new KeyInfo element.  
  291.                     edElement.KeyInfo = new KeyInfo();  
  292.                     // Create a new KeyInfoName element.  
  293.                     KeyInfoName kin = new KeyInfoName();  
  294.                     // Specify a name for the key.  
  295.                     kin.Value = keyName;  
  296.                     // Add the KeyInfoName element.  
  297.                     edElement.KeyInfo.AddClause(kin);  
  298.                 }  
  299.                 // 5. Add the encrypted element data to the EncryptedData object.  
  300.                 edElement.CipherData.CipherValue = encryptedElement;  
  301.                 // 6. Replace the element from the original XmlDocument  
  302.                 // object with the EncryptedData element.  
  303.                 EncryptedXml.ReplaceElement(elementToEncrypt, edElement, bContent);  
  304.                 return true;   
  305.             }  
  306.             catch (System.Exception ex)  
  307.             {  
  308.             }  
  309.             return false;  
  310.         }  
  311.         /// <summary>  
  312.         /// Encrypt a xml element (node) by specified RSA key.  
  313.         /// Actually, it w  
  314.         /// </summary>  
  315.         /// <param name="elementToEncrypt">The element which needs to be encrypted.</param>  
  316.         /// <param name="bContent">Whether to encrypt the element content or not. true to   
  317.         /// encrypt only the contents of the element; false to encrypt the entire element.</param>  
  318.         /// <param name="rsaKey">Specified RSA key, which used to encrypt the session key.</param>  
  319.         /// <param name="keyName">The key name which used to display the <KeyInfo> in encrypted xml.  
  320.         /// It can be empty or null.</param>  
  321.         /// <param name="sessionKey">The specified Symmetric Algorithm key used to encrypt xml element data.</param>  
  322.         /// <returns>If encrypt success, return true, otherwise, return false.</returns>  
  323.         /// <remarks>Actually, I don't think it's a RSA encryption, because the RSA key is only used to  
  324.         /// encrypt the session key, not used to encrypt xml element data.</remarks>  
  325.         public static bool EncryptXmlNode(  
  326.             XmlElement elementToEncrypt,  
  327.             bool bContent,  
  328.             RSA rsaKey,  
  329.             String keyName,   
  330.             SymmetricAlgorithm sessionKey)  
  331.         {  
  332.             if (null == elementToEncrypt || null == rsaKey)  
  333.             {  
  334.                 return false;  
  335.             }  
  336.             try  
  337.             {  
  338.                 // 1. Create a new instance of the EncryptedXml class and use it to   
  339.                 // encrypt the XmlElement with the a new random symmetric key.  
  340.                 // Encrypt the xml's element and get the crypted data.  
  341.                 EncryptedXml eXml = new EncryptedXml();  
  342.                 byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, bContent);  
  343.                 // 2. Construct an EncryptedData object and populate  
  344.                 // it with the desired encryption information.  
  345.                 EncryptedData edElement = new EncryptedData();  
  346.                 edElement.Type = EncryptedXml.XmlEncElementUrl;  
  347.                 // 3. Create an EncryptionMethod element so that the  
  348.                 // receiver knows which algorithm to use for decryption.  
  349.                 edElement.EncryptionMethod = CreateEncryptionMethod(sessionKey, false, false);  
  350.                 // 4. Encrypt the session key and add it to an EncryptedKey element.  
  351.                 EncryptedKey ek = new EncryptedKey();  
  352.                 byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);  
  353.                 ek.CipherData = new CipherData(encryptedKey);  
  354.                 ek.EncryptionMethod = CreateEncryptionMethod(rsaKey, false, false);  
  355.                 // 5. Set the KeyInfo element to specify the name of the RSA key.  
  356.                 if (null != keyName && !keyName.Equals(String.Empty))  
  357.                 {  
  358.                     // Create a new KeyInfo element.  
  359.                     edElement.KeyInfo = new KeyInfo();  
  360.                     // Create a new KeyInfoName element.  
  361.                     KeyInfoName kin = new KeyInfoName();  
  362.                     // Specify a name for the key.  
  363.                     kin.Value = keyName;  
  364.                     // Add the KeyInfoName element to the EncryptedKey object.  
  365.                     ek.KeyInfo.AddClause(kin);  
  366.                 }  
  367.                 // 6. Add the encrypted key to the EncryptedData object.  
  368.                 edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));  
  369.                 // Add the encrypted element data to the EncryptedData object.  
  370.                 edElement.CipherData.CipherValue = encryptedElement;  
  371.                 // 7. Replace the element from the original XmlDocument  
  372.                 // object with the EncryptedData element.  
  373.                 EncryptedXml.ReplaceElement(elementToEncrypt, edElement, bContent);  
  374.                 return true;  
  375.             }  
  376.             catch (System.Exception ex)  
  377.             {  
  378.             }  
  379.             return false;  
  380.         }  
  381.         /// <summary>  
  382.         /// Encrypt a xml file's elements by specified key.  
  383.         /// </summary>  
  384.         /// <param name="filePath">The path of xml file which needs to be encrypted.</param>  
  385.         /// <param name="elementName">The element (node) in xml file which needs to be encrypted.</param>  
  386.         /// <param name="bContent">Whether to encrypt the element content or not. true to   
  387.         /// encrypt only the contents of the element; false to encrypt the entire element.</param>  
  388.         /// <param name="key">The specified encryption key.</param>  
  389.         /// <param name="keyName">The key name which used to display the <KeyInfo> in encrypted xml.  
  390.         /// It can be empty or null.</param>  
  391.         /// <returns>If encrypt success, return true, otherwise, return false.</returns>  
  392.         /// <remarks>After encryption success, it'll save the new data into xml file.</remarks>  
  393.         /// <summary>  
  394.         /// Decrypt a xml file's elements by specified key.  
  395.         /// </summary>  
  396.         /// <param name="filePath">The path of xml file which needs to be decrypted.</param>  
  397.         /// <param name="key">The specified decryption key which used to encrypt before.</param>  
  398.         /// <param name="keyName">The key name which used to display the <KeyInfo> in encrypted xml.  
  399.         /// It can be empty or null.</param>  
  400.         /// <returns>If decrypt success, return true, otherwise, return false.</returns>  
  401.         /// <remarks>After decryption success, it'll save the new data into xml file.</remarks>  
  402.         public static bool DecryptXmlFile(String filePath, object key, String keyName)  
  403.         {  
  404.             if (File.Exists(filePath) && Path.GetExtension(filePath).ToLower().Equals(".xml") &&  
  405.                 null != key)  
  406.             {  
  407.                 XmlDocument xmlDoc = new XmlDocument();  
  408.                 xmlDoc.PreserveWhitespace = true;  
  409.                 xmlDoc.Load(filePath);  
  410.                 if (DecryptXmlDoc(xmlDoc, key, keyName))  
  411.                 {  
  412.                     xmlDoc.Save(filePath);  
  413.                     return true;  
  414.                 }  
  415.                 return false;  
  416.             }  
  417.             return false;  
  418.         }  
  419.         /// <summary>  
  420.         /// Decrypt a xml document's elements by specified key.  
  421.         /// </summary>  
  422.         /// <param name="xmlDoc">The XmlDocument object which needs to be decrypted.</param>  
  423.         /// <param name="key">The specified decryption key which used to encrypt before.</param>  
  424.         /// <param name="keyName">The key name which used to display the <KeyInfo> in encrypted xml.  
  425.         /// It can be empty or null.</param>  
  426.         /// <returns>If decrypt success, return true, otherwise, return false.</returns>  
  427.         public static bool DecryptXmlDoc(XmlDocument xmlDoc, object key, String keyName)  
  428.         {  
  429.             try  
  430.             {  
  431.                 // First, we try to decrypt xml document with EncryptedXml.DecryptDocument() method,   
  432.                 // this method decrypts all <EncryptedData> elements of the XML document, but its precondition  
  433.                 // is that the <EncryptedData> elements has been specified <KeyInfo>'s <KeyName>, if this element  
  434.                 // hasn't been specified, it will failed and throw a CryptographicException exception.  
  435.                 // Second, if we hasn't specified key name, we can only decrypt the document with SymmetricAlgorithm  
  436.                 // key, this is restricted to the API of EncryptedXml class.  
  437.                 if (null != keyName && !keyName.Equals(String.Empty))  
  438.                 {  
  439.                     // Create a new EncryptedXml object.  
  440.                     EncryptedXml exml = new EncryptedXml(xmlDoc);  
  441.                     // Add a key-name mapping.  
  442.                     // This method can only decrypt documents that present the specified key name.  
  443.                     exml.AddKeyNameMapping(keyName, key);  
  444.                     // Decrypt the element.  
  445.                     exml.DecryptDocument();  
  446.                     return true;  
  447.                 }  
  448.                 else  
  449.                 {  
  450.                     SymmetricAlgorithm salgKey = null;  
  451.                     RSA rsaKey = null;  
  452.                     if (key is SymmetricAlgorithm)  
  453.                     {  
  454.                         salgKey = key as SymmetricAlgorithm;  
  455.                     }  
  456.                     else if (key is RSA)  
  457.                     {  
  458.                         rsaKey = key as RSA;  
  459.                         salgKey = DecryptKey(xmlDoc, key);  
  460.                     }  
  461.                     else  
  462.                     {  
  463.                         return false;  
  464.                     }  
  465.                     XmlNodeList nodeList = xmlDoc.GetElementsByTagName("EncryptedData");  
  466.                     int nCount = nodeList.Count;  
  467.                     for (int ix = 0; ix < nCount; ++ix)  
  468.                     {  
  469.                         XmlElement encryptedElement = nodeList[0] as XmlElement;  
  470.                         if (null != salgKey)  
  471.                         {  
  472.                             if (!DecryptXmlNode(encryptedElement, salgKey))  
  473.                             {  
  474.                                 return false;  
  475.                             }  
  476.                         }  
  477.                     }  
  478.                     return true;  
  479.                 }  
  480.             }  
  481.             catch (System.Exception ex)  
  482.             {  
  483.             }  
  484.             return false;  
  485.         }  
  486.         /// <summary>  
  487.         /// Decrypt xml element (node) by specified Symmetric Algorithm key.  
  488.         /// </summary>  
  489.         /// <param name="encryptedElement">The xml element which needs to be decrypted.</param>  
  490.         /// <param name="salgKey">Specified Symmetric Algorithm key.</param>  
  491.         /// <returns>If decrypt success, return true, otherwise, return false.</returns>  
  492.         /// <remarks>We can only use Symmetric Algorithm key to decrypt xml element data but RSA,   
  493.         /// because this is restricted to the API of EncryptedXml class. Please note it on MSDN.</remarks>  
  494.         public static bool DecryptXmlNode(XmlElement encryptedElement, SymmetricAlgorithm salgKey)  
  495.         {  
  496.             try  
  497.             {  
  498.                 // 1. Construct an EncryptedData object and populate it   
  499.                 // with the desired encryption information.  
  500.                 EncryptedData edElement = new EncryptedData();  
  501.                 edElement.LoadXml(encryptedElement);  
  502.                 // 2. Create a new instance of the EncryptedXml class and use it    
  503.                 // to encrypt the XmlElement with the symmetric key.  
  504.                 EncryptedXml eXml = new EncryptedXml();  
  505.                 byte[] rgbOutput = eXml.DecryptData(edElement, salgKey);  
  506.                 // 3. Replace the encryptedData element with the plaintext XML element.  
  507.                 eXml.ReplaceData(encryptedElement, rgbOutput);  
  508.                 return true;  
  509.             }  
  510.             catch (System.Exception ex)  
  511.             {  
  512.                   
  513.             }  
  514.             return false;  
  515.         }  
  516.         /// <summary>  
  517.         /// Retrieve the EncryptionMethod object which contain in EncryptionData.  
  518.         /// </summary>  
  519.         /// <param name="keyAlg">Specified encryption algorithm object.</param>  
  520.         /// <param name="isKeyWrapAlgUri">Whether the namespace Uniform Resource Identifier (URI)   
  521.         /// for Wrap algorithm or not. This can be used only the keyAlg is a Symmetric Encryption Algorithm.  
  522.         /// If used this, the isOaep will be ignored.</param>  
  523.         /// <param name="isOaep">Whether to use RSA Optimal Asymmetric Encryption Padding (OAEP)   
  524.         /// encryption algorithm. This can be used only the keyAlg is a RSA Asymmetric.  
  525.         /// If used this, the isKeyWrapAlgUri will be ignored.</param>  
  526.         /// <returns>Return the EncryptionMethod object.</returns>  
  527.         private static EncryptionMethod CreateEncryptionMethod(object keyAlg, bool isKeyWrapAlgUri, bool isOaep)  
  528.         {  
  529.             EncryptionMethod encMethod = new EncryptionMethod();  
  530.             String URI = String.Empty;  
  531.             if (keyAlg is DES)  
  532.             {  
  533.                 encMethod.KeyAlgorithm = EncryptedXml.XmlEncDESUrl;  
  534.                 //encMethod.KeySize = 0; [exception, why?]  
  535.             }  
  536.             else if (keyAlg is Rijndael)  
  537.             {  
  538.                 switch ((keyAlg as Rijndael).KeySize)  
  539.                 {  
  540.                     case 128:  
  541.                         encMethod.KeyAlgorithm = isKeyWrapAlgUri ?  
  542.                             EncryptedXml.XmlEncAES128KeyWrapUrl : EncryptedXml.XmlEncAES128Url;  
  543.                         encMethod.KeySize = 128;  
  544.                         break;  
  545.                     case 192:  
  546.                         encMethod.KeyAlgorithm = isKeyWrapAlgUri ?  
  547.                             EncryptedXml.XmlEncAES192KeyWrapUrl : EncryptedXml.XmlEncAES192Url;  
  548.                         encMethod.KeySize = 192;  
  549.                         break;  
  550.                     case 256:  
  551.                         encMethod.KeyAlgorithm = isKeyWrapAlgUri ?  
  552.                             EncryptedXml.XmlEncAES256KeyWrapUrl : EncryptedXml.XmlEncAES256Url;  
  553.                         encMethod.KeySize = 256;  
  554.                         break;  
  555.                     default:  
  556.                         break;  
  557.                 }  
  558.             }  
  559.             else if (keyAlg is TripleDES)  
  560.             {  
  561.                 encMethod.KeyAlgorithm = isKeyWrapAlgUri ?  
  562.                     EncryptedXml.XmlEncTripleDESKeyWrapUrl : EncryptedXml.XmlEncTripleDESUrl;  
  563.                 //encMethod.KeySize = 0; [exception, why?]  
  564.             }  
  565.             else if (keyAlg is RSA)  
  566.             {  
  567.                 encMethod.KeyAlgorithm = isOaep ?  
  568.                     EncryptedXml.XmlEncRSAOAEPUrl : EncryptedXml.XmlEncRSA15Url;  
  569.             }  
  570.             else  
  571.             {  
  572.                 // Do nothing  
  573.             }  
  574.             return encMethod;  
  575.         }  
  576.         /// <summary>  
  577.         /// Decrypt encryption key (in node of <EncryptedKey>) which used to encrypt xml element.  
  578.         /// </summary>  
  579.         /// <param name="xmlDoc">The encrypted XmlDocument object.</param>  
  580.         /// <param name="decryptKey">The key which used to decrypt encryption key.  
  581.         /// The key must be Triple DES Key Wrap algorithm or the Advanced Encryption Standard   
  582.         /// (AES) Key Wrap algorithm (also called Rijndael) or RSA key.</param>  
  583.         /// <returns>Return Symmetric Algorithm key object whihc used to decrypt xml element.</returns>  
  584.         private static SymmetricAlgorithm DecryptKey(XmlDocument xmlDoc, object decryptKey)  
  585.         {  
  586.             XmlNodeList encKeyNodeList = xmlDoc.GetElementsByTagName("EncryptedKey");  
  587.             XmlNodeList encDataNodeList = xmlDoc.GetElementsByTagName("EncryptedData");  
  588.             if (encDataNodeList.Count > 0 && encKeyNodeList.Count > 0)  
  589.             {  
  590.                 XmlElement encryptedKey = encKeyNodeList[0] as XmlElement;  
  591.                 EncryptedKey ek = new EncryptedKey();  
  592.                 ek.LoadXml(encryptedKey);  
  593.                 byte[] decryptedData = null;  
  594.                 //if (decryptKey is SymmetricAlgorithm)  
  595.                 if (decryptKey is Rijndael || decryptKey is TripleDES)  
  596.                 {  
  597.                     decryptedData = EncryptedXml.DecryptKey(ek.CipherData.CipherValue, (SymmetricAlgorithm)decryptKey);  
  598.                 }  
  599.                 else if (decryptKey is RSA)  
  600.                 {  
  601.                     // kek is an RSA key: get fOAEP from the algorithm, default to false  
  602.                     bool fOAEP = (ek.EncryptionMethod != null && ek.EncryptionMethod.KeyAlgorithm == EncryptedXml.XmlEncRSAOAEPUrl);  
  603.                     decryptedData = EncryptedXml.DecryptKey(ek.CipherData.CipherValue, (RSA)decryptKey, fOAEP);  
  604.                 }  
  605.                 else  
  606.                 {  
  607.                     // The key (decryptKey) used to decrypt encryption data key is not the Triple DES Key Wrap algorithm  
  608.                     // or the Advanced Encryption Standard (AES) Key Wrap algorithm (also called Rijndael).  
  609.                     return null;  
  610.                 }  
  611.                 XmlElement encryptDataXml = encDataNodeList[0] as XmlElement;  
  612.                 EncryptedData encryptData = new EncryptedData();  
  613.                 encryptData.LoadXml(encryptDataXml);  
  614.                 return GenerateSyAlgKey(decryptedData, encryptData.EncryptionMethod);  
  615.             }  
  616.             return null;  
  617.         }  
  618.         /// <summary>  
  619.         /// Generate a Symmetric Algorithm key by specified key data and EncryptionMethod object.  
  620.         /// </summary>  
  621.         /// <param name="decryptedKeyData">Key data.</param>  
  622.         /// <param name="encMethod">The EncryptionMethod object.</param>  
  623.         /// <returns>Return Symmetric Algorithm key object whihc used to decrypt xml element.</returns>  
  624.         private static SymmetricAlgorithm GenerateSyAlgKey(byte[] decryptedKeyData, EncryptionMethod encMethod)  
  625.         {  
  626.             if (null == encMethod || null == decryptedKeyData || 0 == decryptedKeyData.Length)  
  627.             {  
  628.                 return null;  
  629.             }  
  630.             String keyAlg = encMethod.KeyAlgorithm;  
  631.             int keySize = encMethod.KeySize;  
  632.             SymmetricAlgorithm symAlg = null;  
  633.             if (keyAlg.Equals(EncryptedXml.XmlEncDESUrl))  
  634.             {  
  635.                 symAlg = SymmetricAlgorithm.Create("DES");  
  636.                 symAlg.Key = decryptedKeyData;  
  637.             }  
  638.             else if (keyAlg.Equals(EncryptedXml.XmlEncAES128Url) || keyAlg.Equals(EncryptedXml.XmlEncAES128KeyWrapUrl))  
  639.             {  
  640.                 symAlg = SymmetricAlgorithm.Create("Rijndael");  
  641.                 symAlg.KeySize = 128;  
  642.                 symAlg.Key = decryptedKeyData;  
  643.             }  
  644.             else if (keyAlg.Equals(EncryptedXml.XmlEncAES192Url) || keyAlg.Equals(EncryptedXml.XmlEncAES192KeyWrapUrl))  
  645.             {  
  646.                 symAlg = SymmetricAlgorithm.Create("Rijndael");  
  647.                 symAlg.KeySize = 192;  
  648.                 symAlg.Key = decryptedKeyData;  
  649.             }  
  650.             else if (keyAlg.Equals(EncryptedXml.XmlEncAES256Url) || keyAlg.Equals(EncryptedXml.XmlEncAES256KeyWrapUrl))  
  651.             {  
  652.                 symAlg = SymmetricAlgorithm.Create("Rijndael");  
  653.                 symAlg.KeySize = 256;  
  654.                 symAlg.Key = decryptedKeyData;  
  655.             }  
  656.             else if (keyAlg.Equals(EncryptedXml.XmlEncTripleDESUrl) || keyAlg.Equals(EncryptedXml.XmlEncTripleDESKeyWrapUrl))  
  657.             {  
  658.                 symAlg = SymmetricAlgorithm.Create("TripleDES");  
  659.                 symAlg.Key = decryptedKeyData;  
  660.             }  
  661.             else  
  662.             {  
  663.             }  
  664.             return symAlg;  
  665.         }  
  666.     }  
  667. }  
 

测试代码:

[c-sharp] view plain copy
  1. using System;  
  2. using System.IO;  
  3. using System.Security.Cryptography;  
  4. using System.Text;  
  5. using System.Xml;  
  6. using GTXUtility.Security.Crypt;  
  7. namespace TestUtility  
  8. {  
  9.     public class TestXmlCrypt  
  10.     {  
  11.         enum PrintTypes  
  12.         {  
  13.             PrintOriginal,  
  14.             PrintEncrypt,   
  15.             PrintDecrypt  
  16.         }  
  17.         public static void UseDemo()  
  18.         {  
  19.             Console.WriteLine("Test Xml Crypt begin...");  
  20.             Console.WriteLine("Input file path: (You can drag a file into console without input file path)");  
  21.             String filePath = Console.ReadLine();  
  22.             if (File.Exists(filePath))  
  23.             {  
  24.                 PrintXml(filePath, PrintTypes.PrintOriginal);  
  25.                 Console.WriteLine("Select Symmetric/Asymmetric(RSA) Algorithm, 0: Symmetric, 1: Asymmetric (Default is Symmetric)");  
  26.                 String alg = Console.ReadLine();  
  27.                 int nAlg = alg.Equals("1") ? 1 : 0;  
  28.                 switch (nAlg)  
  29.                 {  
  30.                     case 0:  
  31.                         TestSymmetricAlgorithm(filePath);  
  32.                         break;  
  33.                     case 1:  
  34.                         TestAsymmetricAlgorithm(filePath);  
  35.                         break;  
  36.                     default:  
  37.                         break;  
  38.                 }  
  39.             }  
  40.             Console.WriteLine("Test Xml Crypt end...");  
  41.         }  
  42.         private static void TestSymmetricAlgorithm(String filePath)  
  43.         {  
  44.             Console.WriteLine("Select the encrypt/decrypt algorithm: (Default is DES)");  
  45.             GTXXmlCrypt.SymmetricAlgTypes salTypeTemp = GTXXmlCrypt.SymmetricAlgTypes.DES;  
  46.             for (; salTypeTemp <= GTXXmlCrypt.SymmetricAlgTypes.TripleDES; ++salTypeTemp)  
  47.             {  
  48.                 Console.WriteLine("{0} is {1}", (int)salTypeTemp, salTypeTemp.ToString());  
  49.             }  
  50.             // Read the symmetric algorithm command  
  51.             String algString = Console.ReadLine();  
  52.             GTXXmlCrypt.SymmetricAlgTypes salType = GTXXmlCrypt.SymmetricAlgTypes.DES;  
  53.             try  
  54.             {  
  55.                 salType = (GTXXmlCrypt.SymmetricAlgTypes)Convert.ToInt32(algString);  
  56.                 if (salType <= GTXXmlCrypt.SymmetricAlgTypes.DES &&  
  57.                     salType >= GTXXmlCrypt.SymmetricAlgTypes.TripleDES)  
  58.                 {  
  59.                     salType = GTXXmlCrypt.SymmetricAlgTypes.DES;  
  60.                 }  
  61.             }  
  62.             catch (System.Exception ex)  
  63.             {  
  64.                 salType = GTXXmlCrypt.SymmetricAlgTypes.DES;  
  65.             }  
  66.             // Read the node which we want to encrypt/decrypt  
  67.             Console.WriteLine("Input the XML element node:");  
  68.             String elementName = Console.ReadLine();  
  69.             Console.WriteLine("Encrypt node element or its content, 0: Element, 1: Only content (Default is Element)");  
  70.             String content = Console.ReadLine();  
  71.             bool bContent = content.Equals("1") ? true : false;  
  72.             SymmetricAlgorithm sal = GTXXmlCrypt.CreateSymmetricAlgorithm(salType);  
  73.             if (GTXXmlCrypt.EncryptXmlFile(filePath, elementName, bContent, sal, "abc"))  
  74.             {  
  75.                 // Print the encrypted XML to console  
  76.                 Console.WriteLine("Encrypt XML with {0} algorithm Succeed!", salType);  
  77.                 PrintXml(filePath, PrintTypes.PrintEncrypt);  
  78.                 if (GTXXmlCrypt.DecryptXmlFile(filePath, sal, /*"abc"*/""))  
  79.                 {  
  80.                     // Print the decrypted XML to console  
  81.                     Console.WriteLine("Decrypt XML with {0} algorithm Succeed!", salType);  
  82.                     PrintXml(filePath, PrintTypes.PrintDecrypt);  
  83.                 }  
  84.                 else  
  85.                 {  
  86.                     Console.WriteLine("Decrypt with {0} algorithm Failed!", salType);  
  87.                 }  
  88.             }  
  89.             else  
  90.             {  
  91.                 Console.WriteLine("Encrypt with {0} algorithm Failed!", salType);  
  92.             }  
  93.         }  
  94.         private static void TestAsymmetricAlgorithm(String filePath)  
  95.         {  
  96.             String keyContainerName = "rsakey container";  
  97.             RSA rsaKey = GTXXmlCrypt.CreateRSAAlgorithm(keyContainerName);  
  98.             try  
  99.             {  
  100.                 // Read the node which we want to encrypt/decrypt  
  101.                 Console.WriteLine("Input the XML element node:");  
  102.                 String elementName = Console.ReadLine();  
  103.                 Console.WriteLine("Encrypt node element or its content, 0: Element, 1: Only content (Default is Element)");  
  104.                 String content = Console.ReadLine();  
  105.                 bool bContent = content.Equals("1") ? true : false;  
  106.                 if (GTXXmlCrypt.EncryptXmlFile(filePath, elementName, bContent, rsaKey, ""/*"rsakey"*/))  
  107.                 {  
  108.                     // Print the encrypted XML to console  
  109.                     Console.WriteLine("Encrypt XML with RSA algorithm Succeed!");  
  110.                     PrintXml(filePath, PrintTypes.PrintEncrypt);  
  111.                     if (GTXXmlCrypt.DecryptXmlFile(filePath, rsaKey, ""/*"rsakey"*/))  
  112.                     {  
  113.                         PrintXml(filePath, PrintTypes.PrintDecrypt);  
  114.                         Console.WriteLine("Decrypt XML with RSA algorithm Succeed!");  
  115.                     }  
  116.                     else  
  117.                     {  
  118.                         Console.WriteLine("Decrypt XML with RSA algorithm Failed!");  
  119.                     }  
  120.                 }  
  121.                 else  
  122.                 {  
  123.                     Console.WriteLine("Encrypt xml with RSA algorithm Failed!");  
  124.                 }  
  125.             }  
  126.             catch (System.Exception ex)  
  127.             {  
  128.                 Console.WriteLine(ex.Message);  
  129.             }  
  130.             finally  
  131.             {  
  132.                 rsaKey.Clear();  
  133.             }  
  134.         }  
  135.         static void PrintXml(String filePath, PrintTypes printType)  
  136.         {  
  137.             String format = String.Empty;  
  138.             switch (printType)  
  139.             {  
  140.                 case PrintTypes.PrintOriginal:  
  141.                     format = "■ Original file:/n{0}";  
  142.                     break;  
  143.                 case PrintTypes.PrintEncrypt:  
  144.                     format = "■ Encryptd file:/n{0}";  
  145.                     break;  
  146.                 case PrintTypes.PrintDecrypt:  
  147.                     format = "■ Decrypted file:/n{0}";  
  148.                     break;  
  149.             }  
  150.             XmlDocument doc = new XmlDocument();  
  151.             //doc.PreserveWhitespace = true;  
  152.             doc.Load(filePath);  
  153.             XmlWriterSettings xmlSetting = new XmlWriterSettings();  
  154.             xmlSetting.Indent = true;  
  155.             xmlSetting.IndentChars = "/t";  
  156.             xmlSetting.Encoding = Encoding.UTF8;  
  157.                
  158.             MemoryStream stream = new MemoryStream();  
  159.             XmlWriter writer = XmlWriter.Create(stream, xmlSetting);  
  160.                
  161.             doc.Save(writer);  
  162.             doc.Save(filePath);  
  163.             // Reload the file and update the doc.InnerXml property.  
  164.             doc.PreserveWhitespace = true;  
  165.             doc.Load(filePath);  
  166.               
  167.             Console.WriteLine(format, doc.InnerXml);  
  168.         }  
  169.     }  
  170. }  
 

主函数:

[c-sharp] view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. namespace TestUtility  
  6. {  
  7.     class Program  
  8.     {  
  9.         static void Main(string[] args)  
  10.         {  
  11.             TestXmlCrypt.UseDemo();  
  12.         }  
  13.     }  
  14. }  

 

 


 

如果该代码存在问题或者您有好的建议,请第一时间通知我,让我再将这份代码完善一下。

 

哎,CSDN的这个blog编辑器实在是太令人失望了,格式实在是太难调整了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值