使用RsaProtectedConfigurationProvider对不在配置文件中的字符串执行加密

本文关键字:字符串 执行 加密 配置文件 RsaProtectedConfigurationProvider 使用 | 更新日期: 2023-09-27 18:02:35

我的组织要求使用位于生产服务器上的特定System.Configuration.RsaProtectedConfigurationProvider加密敏感的连接字符串。但是,我有一个在数据库中存储连接字符串的应用程序,我想用相同的密钥对这些应用程序执行加密。

我最初的想法是创建一个虚拟配置文件,其中包含对加密提供程序的引用,用一些文本加载它并执行加密,而不必将其写回磁盘。然后我可以从xml中取出密码/明文:

DummyConfig.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <configSections>
  <section name="DummySection" type="virutalConfig.DummySect, virutalConfig, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
 </configSections>
 <DummySection />
 <configProtectedData>
  <providers>
   <add name="MyProvider"
    type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0,&#xD;&#xA; Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a,&#xD;&#xA; processorArchitecture=MSIL"
    keyContainerName="MyKeys"
    useMachineContainer="true" />
  </providers>
 </configProtectedData>
</configuration>

Program.cs:

class Program
    {
        static void Main(string[] args)
        {
            var fileMap = new ExeConfigurationFileMap
            {
                ExeConfigFilename = @"c:'virtconfigtest'DummyConfig.config"
            };
            var config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
            var sect = config.GetSection("DummySection") as DummySect;
            sect.Inf = "this is some plaintext!";
            sect.SectionInformation.ProtectSection("MyProvider");
            //sect.SectionInformation.ForceSave = true;
            //config.Save();
            if (sect.SectionInformation.IsProtected)
            {
                Console.WriteLine("Section is protected. Raw XML:");
                Console.WriteLine(sect.SectionInformation.GetRawXml());
            }
            else
            {
                Console.WriteLine("Section is not protected. Raw XML:");
                Console.WriteLine(sect.SectionInformation.GetRawXml());
            }
            Console.ReadLine();
        }
    }
    public class DummySect : ConfigurationSection
    {
        public DummySect() { }
        [ConfigurationProperty("inf")]
        public string Inf
        {
            get { return (string)this["inf"]; }
            set { this["inf"] = value; }
        }
    }

不幸的是,GetRawXml()只返回明文,而且即使要得到明文,似乎也必须将配置文件写回磁盘。

我可以通过以xml文档的形式从磁盘读取文件来获得我想要的内容,但我宁愿不这样做。无论如何,整个计划相当粗糙,即使没有添加磁盘写入。我必须从提供程序中检索RSA密钥才能做到这一点吗?如果有,怎么做?

使用RsaProtectedConfigurationProvider对不在配置文件中的字符串执行加密

经过一番研究和反复试验,我终于弄明白了如何做到这一点。

配置文件的加密部分是这样的:

 <DummySection configProtectionProvider="MyProvider">
  <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
   xmlns="http://www.w3.org/2001/04/xmlenc#">
   <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
   <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
     <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
     <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
      <KeyName>Rsa Key</KeyName>
     </KeyInfo>
     <CipherData>
      <CipherValue>RsMpDD/wJmmpN+Mme+qFuRVm2Ddk759hWM7HaeAnW7xpfkCoC4ko7vDBmqylzQ0QAFL2wuR8u8Bsf+4xwn++Ru/GsEaYrGrcDMYJTuWElyHuxnw+5umqexQJye2R5uL/91alFVNV41HnSPlwuA+pgk14yHSWIflIyKFmUTx58vU=</CipherValue>
     </CipherData>
    </EncryptedKey>
   </KeyInfo>
   <CipherData>
    <CipherValue>lQI7gyQZ2HIIQUdKsp73HrYcebbOiO4dCriwCt5avfVTcxPZEHzaCfV52k+triRwq64uGVCNRpGUe5PCVEfbWwrPHaNaFzRp</CipherValue>
   </CipherData>
  </EncryptedData>
 </DummySection> 

第一个密文块是一个用RSA加密的三重DES密钥。密钥对可以从目录下的文件中获得:C:'ProgramData'Microsoft'Crypto'RSA'MachineKeys

第二部分用这个DES密钥加密,并加上一个64位初始化向量。令人沮丧的是,它用方法填充:ISO10126

下面是解密的代码:

        var cspParameters = new CspParameters()
        {
             KeyContainerName = "MyKeys",
             Flags = CspProviderFlags.UseMachineKeyStore
        }; //refers to a file in the machine keys directory
        var rsaKey = new RSACryptoServiceProvider(cspParameters);
        var t1 =
            Convert.FromBase64String(
                "RsMpDD/wJmmpN+Mme+qFuRVm2Ddk759hWM7HaeAnW7xpfkCoC4ko7vDBmqylzQ0QAFL2wuR8u8Bsf+4xwn++Ru/GsEaYrGrcDMYJTuWElyHuxnw+5umqexQJye2R5uL/91alFVNV41HnSPlwuA+pgk14yHSWIflIyKFmUTx58vU=");
        var t2 =
            Convert.FromBase64String(
                "lQI7gyQZ2HIIQUdKsp73HrYcebbOiO4dCriwCt5avfVTcxPZEHzaCfV52k+triRwq64uGVCNRpGUe5PCVEfbWwrPHaNaFzRp");
        var desKey = rsaKey.Decrypt(t1, false); //get the des key
        var iv = t2.Take(8).ToArray(); //get the initialization vector
        var ct = t2.Skip(8).ToArray(); //get the actual ciphertext
        var desEnc = new TripleDESCryptoServiceProvider()
        {
            Padding = PaddingMode.ISO10126
        };
        var plaintext = Encoding.Default.GetString(desEnc.CreateDecryptor(desKey, iv).TransformFinalBlock(ct, 0, ct.Length));