我正在使用.NET3.5(C#)开发winforms应用程序。为了保护应用程序,我使用了一个Xml文件,应该使用非对称密钥加密。
现在,我的应用程序有两个部分,windows窗体部分和windows服务部分(检查应用程序的真实性)。因此,我的文件将由两部分加密/解密。这就是问题出现的地方。当win表单部分尝试解密服务已经破坏的文件时,会发生异常(不正确的数据)。这是我的代码:
private readonly static string containerName = "ENC_XML_ASY_KEY";
private readonly static string keyName = "keyName";
public static void EncryptXmlFile(this XmlDocument doc, string elemToEncryptName)
{
if (doc == null)
return;
var cspParams = new CspParameters() { KeyContainerName = containerName };
var rsaKey = new RSACryptoServiceProvider(cspParams);
var elementToEncrypt = doc.GetElementsByTagName(elemToEncryptName)[0] as XmlElement;
if (elementToEncrypt == null)
return;
// Create a 256 bit Rijndael key.
var sessionKey = new RijndaelManaged() { KeySize = 256 };
var eXml = new EncryptedXml();
byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
var edElement = new EncryptedData()
{
Type = EncryptedXml.XmlEncElementUrl,
Id = "XmlID",
EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url)
};
var ek = new EncryptedKey();
var encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
// Create a new KeyInfoName element.
var kin = new KeyInfoName() { Value = keyName };
// Add the KeyInfoName element to the encryptedKey object.
ek.KeyInfo.AddClause(kin);
edElement.CipherData.CipherValue = encryptedElement;
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
}
public static void DecryptXmlFile(this XmlDocument doc)
{
if (doc == null)
return;
var cspParams = new CspParameters() { KeyContainerName = containerName };
var rsaKey = new RSACryptoServiceProvider(cspParams);
var exml = new EncryptedXml(doc);
exml.AddKeyNameMapping(keyName, rsaKey);
exml.DecryptDocument();
}
答案 0 :(得分:1)
您已经指出服务和客户端运行的帐户不同,这解释了为什么它不起作用 - 除非您另行指定,密钥是在用户自己的密钥存储区中创建的,其他用户不会有权访问。
您需要在机器商店和中创建密钥以授予其他用户访问权限(因为默认情况下,即使在机器商店中创建,安全性也适用于密钥只允许访问创建它的用户。)
您还允许解密创建新密钥(如果不存在)(这会导致您的“错误数据”异常,而不是可能更有用的“密钥集不存在”)。
我建议修改加密方法如下:
public static void EncryptXmlFile(this XmlDocument doc, string elemToEncryptName)
{
if (doc == null)
return;
var security = new CryptoKeySecurity();
// Give the creating user full access
security.AddAccessRule(new CryptoKeyAccessRule(new NTAccount(Environment.UserDomainName, Environment.UserName), CryptoKeyRights.FullControl, AccessControlType.Allow));
// Add read-only access to other users as required
security.AddAccessRule(new CryptoKeyAccessRule(new NTAccount("<domain name>", "<user name>"), CryptoKeyRights.GenericRead, AccessControlType.Allow));
// Specify that the key is to be stored in the machine key-store, and apply the security settings created above
var cspParams = new CspParameters
{
KeyContainerName = containerName,
Flags = CspProviderFlags.UseMachineKeyStore,
CryptoKeySecurity = security
};
var rsaKey = new RSACryptoServiceProvider(cspParams);
// Remainder of the method here...
解密方法:
public static void DecryptXmlFile(this XmlDocument doc)
{
if (doc == null)
return;
// Specify that the key is to be loaded from the machine key-store, and not to create a new key if it doesn't exist.
var cspParams = new CspParameters
{
KeyContainerName = containerName,
Flags = CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey
};
var rsaKey = new RSACryptoServiceProvider(cspParams);
// Remainder of the method here...