【问题标题】:unexpected CryptographicException: Keyset does not exist AND CryptographicException: Access is denied意外 CryptographicException:密钥集不存在和 CryptographicException:访问被拒绝
【发布时间】:2011-05-23 10:53:16
【问题描述】:

我们正在尝试在我们的 XP SP2 机器(Win7 之后)上为我们的 C# (.net 3.5) 应用程序执行此操作。

在我们的安装程序(由 VS2008 创建)中,我们使用 AES 密钥和 iv 加密我们的连接字符串,然后创建一个 RSA key-pair 并将它们存储在 MachineKeyStore 中。安装程序将使用RSA public keyAES 密钥和iv 进行加密,并将加密后的密钥和iv 与加密的连接字符串一起存储。

安装后,我们的应用程序会用加密的AES密钥和iv读回加密的连接字符串,并使用RSA private key(来自MachineKeyStore)解密AES密钥和iv然后解密连接字符串使用AES 键和iv。

安装程序和我们的应用程序为MachineKeyStorecontainer name 共享一个constant string

我知道密钥对的存储位置,因此我可以监控它以查看密钥对是否被删除、更新或创建。

我做了一些测试,发现了一些有趣的东西(出乎意料),但不知道为什么会这样。我的用户帐户是管理员帐户。

  1. 安装程序可以删除我们的应用程序创建的存储的key-pair,并立即创建一个具有相同容器名称的新的;
  2. 安装程序可以更新我们的应用程序创建的key-pair(不是删除并重新创建,我认为它是覆盖 - 但根据文档不应该发生这种情况)
  3. 我们的应用程序无法删除安装程序创建的密钥对:当密钥对实际存在时,CryptographicException: Keyset does not exist. 会发生异常;
  4. 当安装程序创建的密钥对存在时,我们的应用程序无法创建新的:CryptographicException: Keyset does not exist.
  5. 我们的应用程序无法访问安装程序创建的密钥对, CryptographicException: Access is denied. 在这种情况下会发生。安装程序中的加密适用于AESRSA public key。当应用尝试使用存储的private key进行解密时,会出现“Access is denied”异常。

我们的代码如下:

public static void CreateRSAKeyPair(string keyContainerName)
        {
            DeleteRSAKeyPair(keyContainerName);

            CspParameters cspParams = new CspParameters();
            cspParams.KeyContainerName = keyContainerName;
            cspParams.Flags |= CspProviderFlags.UseMachineKeyStore;

            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspParams))
            {
                rsa.PersistKeyInCsp = false;
            }
        }



public static void DeleteRSAKeyPair(string keyContainerName)
        {
            CspParameters cspParams = new CspParameters();
            cspParams.KeyContainerName = keyContainerName;
            cspParams.Flags |= CspProviderFlags.UseMachineKeyStore;

            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspParams))
            {
                rsa.PersistKeyInCsp = false;
                try
                {
                    rsa.Clear();
                }
                catch (CryptographicException ex)
                {
                    Log.logItem(LogType.Exception, "RSA key clear error, can be ignored", "SecurityMgr::DeleteRSAKeyPair()", "CryptographicException msg=" + ex.ToString());
                }
            }
        }

访问private key进行解密的代码:

private static byte[] RSADecrypt(byte[] inputData, string keyContainerName)
        {
            byte[] resultData = null;
            try
            {
                CspParameters cspParams = new CspParameters();
                cspParams.Flags |= CspProviderFlags.UseMachineKeyStore;
                cspParams.KeyContainerName = keyContainerName;
                using (RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams))
                {
                    //rsaProvider.PersistKeyInCsp = true;
                    //private key
                    RSAParameters rsaParams = rsaProvider.ExportParameters(true);
                    rsaProvider.ImportParameters(rsaParams);
                    resultData = rsaProvider.Decrypt(inputData, false);
                }
            }
            catch (CryptographicException ex)
            {
                string msg = "CryptographicException: keyContainerName=" + keyContainerName + "\nmsg=" + ex.ToString();
                Log.logItem(LogType.Exception, "RSA decryption exception", "SecurityMgr::RSADecrypt()", msg);
            }
            return resultData;
        }

RSA非对称加密可以这样用吗?

编辑:

对我们应用程序中的连接字符串(不涉及安装程序)执行相同的操作(使用 AES 和 RSA 加密)可以正常工作。

【问题讨论】:

    标签: c# .net security encryption installation


    【解决方案1】:

    实际问题不是很清楚。但是,我在您的代码中看到了一些内容:

    • 您将密钥对(私有和公共)从 Provider 导出到参数中。人们对布尔参数感到困惑。这并不意味着它只导出私钥。如果您将其设置为 true(导出私钥),您的 PUBLIC 和 PRIVATE 密钥都将被导出。
    • 您从 RSA Provider 实例导出的相同密钥,正在导入回同一个提供程序。这没有任何意义。
    • 删除 ExportParameters 和 ImportParameters 行,它们什么也没做。如果您在构造函数中指定的容器名称有效且存在,则您的密钥应该已经在 RSA 提供程序中。
    • 对于非对称加密,您使用 PRIVATE 密钥进行加密,因为您不共享该密钥。然后,您使用 PUBLIC 密钥进行解密,因为对方(接收方)应该只持有您的 PUBLIC 密钥才能解密。如果他们拥有您的私钥,那么整个方案就会受到威胁。

    【讨论】:

    • 对于仍在阅读本文的任何人,从技术上讲,public > private(用公共加密,用私有解密)的过程称为加密,用于对可以解密的单个目标进行加密。反向过程(private > public)称为signing,它验证源的身份(因为只有他们可以“加密”它),但公钥(即任何人)可以“解密”(验证)它。只是安全模型中的一个语义上但重要的区别。
    猜你喜欢
    • 2013-11-25
    • 2016-10-26
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    相关资源
    最近更新 更多