0

我正在使用 .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();
    }
4

1 回答 1

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...
于 2012-06-29T13:36:16.287 回答