C# 意外的CryptographicException:密钥集不存在,CryptographicException:访问被拒绝

C# 意外的CryptographicException:密钥集不存在,CryptographicException:访问被拒绝,c#,.net,security,encryption,installation,C#,.net,Security,Encryption,Installation,我们正试图在XP SP2机器(Win7更高版本)上为C#(.net 3.5)应用程序实现这一点 在我们的安装程序(由VS2008创建)中,我们使用AES密钥和iv加密连接字符串,然后创建RSA密钥对,并将它们存储在MachineKeyStore中。安装程序将使用RSA公钥对AES密钥和iv进行加密,并将加密的密钥和iv与加密的连接字符串一起存储 安装后,我们的应用程序将读取带有加密AES密钥和iv的加密连接字符串,并使用RSA私钥(来自MachineKeyStore)解密AES密钥和iv,然后使

我们正试图在XP SP2机器(Win7更高版本)上为C#(.net 3.5)应用程序实现这一点

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

安装后,我们的应用程序将读取带有加密AES密钥和iv的加密连接字符串,并使用
RSA私钥
(来自
MachineKeyStore
)解密
AES
密钥和iv,然后使用
AES
密钥和iv解密连接字符串

对于
MachineKeyStore
容器名称
,安装程序和我们的应用程序共享一个
常量字符串

我知道密钥对存储在哪里,所以我可以监视它以查看是否删除、更新或创建了密钥对

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

  • 安装程序可以删除由我们的应用程序创建的存储的
    密钥对
    ,并立即创建一个具有相同容器名称的新密钥对
  • 安装程序可以更新由我们的应用程序创建的
    密钥对
    (不要删除并再次创建,我认为它正在覆盖-但根据文档,这不应该发生)
  • 我们的应用程序无法删除安装程序创建的密钥对:
    加密异常:密钥集不存在。
    当密钥对实际存在时,将发生异常
  • 当安装程序创建的密钥对存在时,我们的应用程序无法创建新的密钥对:
    加密异常:密钥集不存在。
  • 我们的应用程序无法访问安装程序创建的密钥对,
    加密异常:访问被拒绝。
    在这种情况下会发生。安装程序中的加密使用
    AES
    RSA公钥
    。当应用程序尝试使用存储的
    私钥
    进行解密时,将发生“
    访问被拒绝
    ”异常
  • 我们的守则如下:

    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 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加密)(不涉及安装程序)效果良好。

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

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

    对于仍在阅读本文的任何人,从技术上讲,public>private(用public加密,用private解密)的过程称为加密,用于对能够解密的单个目标进行加密。反向过程(private>public)称为签名,它验证源的身份(因为只有他们可以“加密”它),但公钥(即任何人)可以“解密”(验证)它。这只是安全模型中语义上的一个重要区别。