我编写的应用程序需要从互联网上下载加密的 XML 文件,解密并从中获取一些信息。
出于测试目的,我将我的 XML 文件放在公共链接中,当我运行应用程序时,我的行为不一致。
这是我的代码,它获取加密文件并使用我的解密方法对其进行解密:
const string settingsFileUrl = @"sharedlink.com...";
XmlDocument myXmlDocument = new XmlDocument();
myXmlDocument.Load(settingsFileUrl);
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = @"gf154de4-12f1-430a-8210-63fde92fbb17";
//This private key is here just for testing purpose
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
Utilities.Decryptor.Decrypt(myXmlDocument, rsaKey, "rsaKey");
这是我的解密代码:
internal class Decryptor
{
public static void Decrypt(XmlDocument Doc, RSA Alg, string KeyName)
{
// Check the arguments.
if (Doc == null)
throw new ArgumentNullException("Doc");
if (Alg == null)
throw new ArgumentNullException("Alg");
if (KeyName == null)
throw new ArgumentNullException("KeyName");
// Create a new EncryptedXml object.
EncryptedXml exml = new EncryptedXml(Doc);
// Add a key-name mapping.
// This method can only decrypt documents
// that present the specified key name.
exml.AddKeyNameMapping(KeyName, Alg);
// Decrypt the element.
exml.DecryptDocument();
}
}
当我在我的主机上调试这段代码时,一切都像一个魅力。当我在我的辅助机器上调试它时,我从行中收到错误“bad data”Utilities.Decryptor.Decrypt(myXmlDocument, rsaKey, "rsaKey");
我仔细检查了,我的辅助机器可以访问 xml 文件。我不知道可能是什么问题。请帮忙 :-(
更新:这是我的加密代码:
public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string KeyName)
{
// Check the arguments.
if (Doc == null)
throw new ArgumentNullException("Doc");
if (ElementToEncrypt == null)
throw new ArgumentNullException("ElementToEncrypt");
if (EncryptionElementID == null)
throw new ArgumentNullException("EncryptionElementID");
if (Alg == null)
throw new ArgumentNullException("Alg");
if (KeyName == null)
throw new ArgumentNullException("KeyName");
////////////////////////////////////////////////
// Find the specified element in the XmlDocument
// object and create a new XmlElemnt object.
////////////////////////////////////////////////
XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
// Throw an XmlException if the element was not found.
if (elementToEncrypt == null)
{
throw new XmlException("The specified element was not found");
}
RijndaelManaged sessionKey = null;
try
{
//////////////////////////////////////////////////
// Create a new instance of the EncryptedXml class
// and use it to encrypt the XmlElement with the
// a new random symmetric key.
//////////////////////////////////////////////////
// Create a 256 bit Rijndael key.
sessionKey = new RijndaelManaged();
sessionKey.KeySize = 256;
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;
// Create an EncryptionMethod element so that the
// receiver knows which algorithm to use for decryption.
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
// Encrypt the session key and add it to an EncryptedKey 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 the DataReference to the EncryptedKey.
ek.AddReference(dRef);
// Add the encrypted key to the
// EncryptedData object.
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
// Set the KeyInfo element to specify the
// name of the RSA key.
// Create a new KeyInfoName element.
KeyInfoName kin = new KeyInfoName();
// Specify a name for the key.
kin.Value = KeyName;
// 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)
{
// re-throw the exception.
throw e;
}
finally
{
if (sessionKey != null)
{
sessionKey.Clear();
}
}
}
也许会有所帮助
更新 2:
我在 ( MSDN ) 上找到了有关加密方法的用户评论。他写了下一条评论:发布的样本不起作用,因为它们没有使用相同的键。不仅在不同的机器上:在同一台机器上运行程序两次也不应该工作(对我不起作用),因为它们每次都使用不同的随机密钥。创建密钥后尝试添加此代码:
key = new RijndaelManaged();
byte[] passwordBytes = Encoding.UTF8.GetBytes("Password1234"); //password here
byte[] saltBytes = Encoding.UTF8.GetBytes("Salt"); // salt here (another string)
PasswordDeriveBytes p = new PasswordDeriveBytes(passwordBytes, saltBytes);
// sizes are devided by 8 because [ 1 byte = 8 bits ]
key.IV = p.GetBytes(key.BlockSize / 8);
key.Key = p.GetBytes(key.KeySize / 8);
现在程序使用相同的密钥和初始向量,加密和解密应该可以在所有机器上工作。另外,请考虑将密钥重命名为算法,否则这是非常误导的。我会说这是来自 MSDN 的一个糟糕的、运行不佳的示例。
我尝试使用它,但我不确定在解密方法中我需要在哪里提供哪个密钥。也许你会比我更了解它。谢谢