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

来源:互联网 发布:太阳系3d软件 编辑:程序博客网 时间:2024/06/11 15:33

原文地址: http://blog.csdn.net/woyaowenzi/article/details/6573952 


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

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

1.     加密算法的选取。

2.     如何进行加密。

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

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

 


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

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

XML Encryption Syntax and Processing(W3C XML加解密标准文档

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

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

[xhtml] view plaincopy
  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 plaincopy
  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关于加密的标准。可参见XML Encryption Syntax and Processing文档。


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

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

 

[xhtml] view plaincopy
  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 plaincopy
  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.  public byte[] EncryptData(XmlElement inputElementSymmetricAlgorithm symmetricAlgorithmbool content);

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

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

2.  public byte[] DecryptData(EncryptedData encryptedDataSymmetricAlgorithm symmetricAlgorithm);

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

3.  public void DecryptDocument();

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

4.  public static void ReplaceElement(XmlElement inputElementEncryptedData encryptedDatabool content);

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

5.  public static byte[] DecryptKey(byte[] keyDataSymmetricAlgorithm symmetricAlgorithm);

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

6.  public static byte[] DecryptKey(byte[] keyDataRSA rsabool useOAEP);

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

 

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

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

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

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

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

 

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

 

[c-sharp] view plaincopy
  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 plaincopy
  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, falsefalse);  
  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. }  
 

 

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

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

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

3. 创建 EncryptionMethod 对象,该对象被初始化为用来生成密钥的加密算法的 URL 标识符。将 EncryptionMethod 对象传递给 EncryptionMethod 属性。

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

5. 将加密的元素数据添加到 EncryptedData 对象中。

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

 

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

以下是解密的代码:

[c-sharp] view plaincopy
  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;  

解密分两步:

1.     如果给出了keyName和解密密钥,那么直接使用EncryptedXml的DecryptDocument方法。

2.     否则,我们就需要一个节点一个节点的解密了。对于非对称的解密,一般直接使用DecryptDocument方法就可以了。

 


整个代码如下:

GTXXmlCrypt代码:

[c-sharp] view plaincopy
  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, falsefalse);  
  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, falsefalse);  
  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, falsefalse);  
  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 plaincopy
  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 plaincopy
  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 0