我编写了一些代码,这些代码加密了包含用户凭据的XML配置文件,以及解密该文件的代码。当我在本地计算机上一起运行加密和解密时,它按预期工作。但是,当我部署程序时,只使用解密代码,xml文件将不会解密。我得到一个加密异常:错误的数据? 这是我的代码:
public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string Keyname)
{
if (Doc == null)
throw new ArgumentNullException("Doc");
if (ElementToEncrypt == null)
throw new ArgumentNullException("Element to Encrypt");
if (EncryptionElementID == null)
throw new ArgumentNullException("EncryptionElementID");
if (Alg == null)
throw new ArgumentNullException("ALG");
//specify which xml elements to encrypt
XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
if (elementToEncrypt == null)
throw new XmlException("The specified element was not found");
try
{
//create session key
RijndaelManaged sessionkey = new RijndaelManaged();
sessionkey.KeySize = 256;
//encrypt using Encrypted exml object and hold in byte array
EncryptedXml exml = new EncryptedXml();
byte[] encryptedElement = exml.EncryptData(elementToEncrypt, sessionkey, false);
//Construct an EncryptedData object and populate
// it with the desired encryption information.
EncryptedData edElement = new EncryptedData();
edElement.Type = EncryptedXml.XmlEncElementUrl;
edElement.Id = EncryptionElementID;
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
//encrypt the session key and add it encrypted key element
EncryptedKey ek = new EncryptedKey();
byte[] encryptedKey = EncryptedXml.EncryptKey(sessionkey.Key, Alg, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
// Create a new DataReference element
// for the KeyInfo element. This optional
// element specifies which EncryptedData
// uses this key. An XML document can have
// multiple EncryptedData elements that use
// different keys.
DataReference dRef = new DataReference();
// Specify the EncryptedData URI.
dRef.Uri = "#" + EncryptionElementID;
//add data reference to encrypted key
ek.AddReference(dRef);
//Add the encrypted key to the
// EncryptedData object.
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
// Create a new KeyInfoName element.
KeyInfoName kin = new KeyInfoName();
// Add the KeyInfoName element to the
// EncryptedKey object.
ek.KeyInfo.AddClause(kin);
// Add the encrypted element data to the
// EncryptedData object.
edElement.CipherData.CipherValue = encryptedElement;
////////////////////////////////////////////////////
// Replace the element from the original XmlDocument
// object with the EncryptedData element.
////////////////////////////////////////////////////
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
}
catch (Exception e)
{
throw e;
}
}
public static string Decrypt()
{
//create XML documentobject and load config file
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.Load("config.xml");
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
//create container for key
CspParameters cspParam = new CspParameters();
cspParam.KeyContainerName = "XML_RSA_FTP_KEY";
cspParam.Flags = CspProviderFlags.UseMachineKeyStore;
//create key and store in container
RSACryptoServiceProvider ftpkey = new RSACryptoServiceProvider(cspParam);
//add keyname mapping qnd decrypt the document
EncryptedXml exml = new EncryptedXml(xmlDoc);
exml.AddKeyNameMapping("ftpkey", ftpkey);
exml.DecryptDocument();
//pass decrypted document to extract credentials method
string details = Extract_Credentials(xmlDoc);
//return decrypted log in details
return details;
}
任何帮助将不胜感激。谢谢,达伦
答案 0 :(得分:1)
我将您的加密功能更改为不传入RSA Alg,而是使用字符串Keyname param创建RSACryptoServiceProvider rsaAlg,这应该与KeyContainerName的Decrypt中使用的字符串相同,“XML_RSA_FTP_KEY”
在尝试解密另一台PC时,解密功能抛出“错误数据”异常的原因是CspParameters链接到运行加密的PC上的会话。
需要在XML中嵌入和加密cspParams对象,以便在另一台PC上启用Decryption。幸运的是,我们可以使用EncryptionProperty。
public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, string Keyname)
{
if (Doc == null)
throw new ArgumentNullException("Doc");
if (ElementToEncrypt == null)
throw new ArgumentNullException("Element to Encrypt");
if (EncryptionElementID == null)
throw new ArgumentNullException("EncryptionElementID");
// Create a CspParameters object and specify the name of the key container.
var cspParams = new CspParameters { KeyContainerName = Keyname }; //"XML_RSA_FTP_KEY"
// Create a new RSA key and save it in the container. This key will encrypt
// a symmetric key, which will then be encryped in the XML document.
var rsaAlg = new RSACryptoServiceProvider(cspParams);
//specify which xml elements to encrypt
XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
if (elementToEncrypt == null)
throw new XmlException("The specified element was not found");
try
{
//create session key
RijndaelManaged sessionkey = new RijndaelManaged();
sessionkey.KeySize = 256;
//encrypt using Encrypted exml object and hold in byte array
EncryptedXml exml = new EncryptedXml();
byte[] encryptedElement = exml.EncryptData(elementToEncrypt, sessionkey, false);
//Construct an EncryptedData object and populate
// it with the desired encryption information.
EncryptedData edElement = new EncryptedData();
edElement.Type = EncryptedXml.XmlEncElementUrl;
edElement.Id = EncryptionElementID;
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
//encrypt the session key and add it encrypted key element
EncryptedKey ek = new EncryptedKey();
byte[] encryptedKey = EncryptedXml.EncryptKey(sessionkey.Key, rsaAlg, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
// Create a new DataReference element
// for the KeyInfo element. This optional
// element specifies which EncryptedData
// uses this key. An XML document can have
// multiple EncryptedData elements that use
// different keys.
DataReference dRef = new DataReference();
// Specify the EncryptedData URI.
dRef.Uri = "#" + EncryptionElementID;
//add data reference to encrypted key
ek.AddReference(dRef);
//Add the encrypted key to the
// EncryptedData object.
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
// Save some more information about the key using the EncryptionProperty element.
// Create a new "EncryptionProperty" XmlElement object.
var property = new XmlDocument().CreateElement("EncryptionProperty", EncryptedXml.XmlEncNamespaceUrl);
// Set the value of the EncryptionProperty" XmlElement object.
property.InnerText = RijndaelManagedEncryption.EncryptRijndael(Convert.ToBase64String(rsaAlg.ExportCspBlob(true)),
"Your Salt string here");
// Create the EncryptionProperty object using the XmlElement object.
var encProperty = new EncryptionProperty(property);
// Add the EncryptionProperty object to the EncryptedKey object.
ek.AddProperty(encProperty);
// Create a new KeyInfoName element.
KeyInfoName kin = new KeyInfoName();
// Add the KeyInfoName element to the
// EncryptedKey object.
ek.KeyInfo.AddClause(kin);
// Add the encrypted element data to the
// EncryptedData object.
edElement.CipherData.CipherValue = encryptedElement;
////////////////////////////////////////////////////
// Replace the element from the original XmlDocument
// object with the EncryptedData element.
////////////////////////////////////////////////////
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
}
catch (Exception)
{
throw;
}
}
public static string Decrypt()
{
//create XML documentobject and load config file
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.Load("config.xml");
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
//create container for key
CspParameters cspParam = new CspParameters();
cspParam.KeyContainerName = "XML_RSA_FTP_KEY";
cspParam.Flags = CspProviderFlags.UseMachineKeyStore;
//create key and store in container
RSACryptoServiceProvider ftpkey = new RSACryptoServiceProvider(cspParam);
var keyInfo = xmlDoc.GetElementsByTagName("EncryptionProperty")[0].InnerText;
ftpkey.ImportCspBlob(
Convert.FromBase64String(RijndaelManagedEncryption.DecryptRijndael(keyInfo,
"Your Salt string here")));
//add keyname mapping qnd decrypt the document
EncryptedXml exml = new EncryptedXml(xmlDoc);
exml.AddKeyNameMapping("ftpkey", ftpkey);
exml.DecryptDocument();
//pass decrypted document to extract credentials method
string details = Extract_Credentials(xmlDoc);
//return decrypted log in details
return details;
}
查看RijndaelManagedEncryption类的here。
答案 1 :(得分:0)
显而易见的问题是如何将XML_RSA_FTP_KEY私钥移动到服务器。
如果您没有执行任何操作,decrypt()
- 方法将在XML_RSA_FTP_KEY容器中生成新的密钥对。此密钥将无法解密使用不同密钥加密的数据,并提供“错误数据” - 例外。
答案 2 :(得分:0)
使用EncryptedXml类,X.509证书时,我收到了同样的错误,我忘了授予对解密过程的进程/任务所有者的证书私钥的访问权限。所以,不要忘记授予对私钥的访问权限!
我知道当您共享web.config文件时,在web-farm中使用自定义/共享RSA-CSP密钥加密的所有服务器,您还需要将容器中的密钥共享给所有服务器。需要解密web.config中的密文。从服务器场中的每个服务器上的容器导入密钥后,您需要授予对IIS应用程序运行的应用程序池标识的访问权限。请参阅aspnet_regiis.exe工具的-pc,-px,-pi和-pa参数,了解如何分别创建,导出,导入和授权对RSA密钥的访问(http://msdn.microsoft.com/en-us/library/k6h9cz8h.ASPX)。这是另一个很好的资源:http://msdn.microsoft.com/en-us/library/2w117ede.aspx。
为了使这在实践中更具确定性,我在IIS中在域服务帐户下运行我的应用程序,创建了一个自定义共享RSA密钥,在我的Web场中导入,被授予对域服务帐户密钥的访问权限,以及然后使用特定密钥加密web.config的敏感部分(请参阅aspnet_regiis.exe上的-pef和-pdf参数)。
如果您要加密应用程序设置,您可能需要考虑创建自定义app.config / web.config部分(如果您不热衷于加密所有“appSettings”)。然后,使用aspnet_regiis.exe使用Right键对其进行加密。最后,在部署过程中分发受保护的web.config(您可能会将加密的web.config与应用程序一起打包)。内置的configProtectionProvider透明地加密/解密app.config和web.config部分非常方便。
以下是文件中此类加密部分的示例:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="secureAppSettings" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<configProtectedData>
<providers>
<add name="MyKeyProvider"
type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
keyContainerName="MyKey"
useMachineContainer="true" />
</providers>
</configProtectedData>
<secureAppSettings configProtectionProvider="MyKeyProvider">
<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>deadbeef</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>cafef00d</CipherValue>
</CipherData>
</EncryptedData>
</secureAppSettings>
</configuration>
正如您所看到的,开箱即用的配置保护使用相同的XML EncryptedData框架,但只为您完成所有加密工作。如果您正确授予对私钥的访问权限,这对Windows服务和桌面应用程序的工作方式相同。