简体   繁体   English

X509Certificate2:使用私钥解密时访问被拒绝

[英]X509Certificate2: Access denined when decrypting with privatekey

I have the following code which is used for (en/de)crypting a key which in turn is used for encrypting strings that are placed in clients headers some of which the application may cache. 我有以下代码,用于(加密)解密密钥,该密钥又用于加密放置在客户端标头中的字符串,应用程序可能会缓存其中的一些字符串。 (they contain senstive information). (它们包含敏感信息)。 The application in this case is ASP .Net core 2.0 running on IIS. 在这种情况下,该应用程序是在IIS上运行的ASP .Net core 2.0。

The encryption using the public key works just fine but the exception is thrown when i try to decrypt. 使用公共密钥的加密工作得很好,但是当我尝试解密时会抛出异常。

    private string DecryptKey(string key)
    {
        if (this.Certificate == null || string.IsNullOrEmpty(key))
            throw new Exception("A x509 certificate and string for decryption must be provided");

        // Get the string as bytes
        var encryptedBytes = Convert.FromBase64String(key);

        if (!Certificate.HasPrivateKey)
            throw new Exception("x509 certificate does not contain a private key for decryption");

        using (var rsa = Certificate.GetRSAPrivateKey())
        {
            var result = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA512); // **Exception is thrown here**
            return ASCIIEncoding.ASCII.GetString(result);
        }
    }

    private string EncryptKey(string key)
    {
        if (this.Certificate == null || string.IsNullOrEmpty(key))
            throw new Exception("A x509 certificate and string for decryption must be provided");

        // Get the string as bytes
        var bytes = ASCIIEncoding.ASCII.GetBytes(key);

        if (!Certificate.HasPrivateKey)
            throw new Exception("x509 certificate does not contain a private key for decryption");

        using (var rsa = Certificate.GetRSAPrivateKey())
        {
            var result = rsa.Encrypt(bytes, RSAEncryptionPadding.OaepSHA512);
            return Convert.ToBase64String(result);
        }
    }

    /// <summary>
    /// Returns a X509Certificate2 with the given name
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    protected X509Certificate2 GetX509Certificate(string name)
    {
        // Get the certificate store for the current user.
        var store = new X509Store(StoreLocation.LocalMachine);

        try
        {
            store.Open(OpenFlags.ReadOnly);

            // Place all certificates in an X509Certificate2Collection object.
            var certCollection = store.Certificates;

            var currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
            var signingCert = currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, name, false);

            if (signingCert.Count == 0)
                return null;

            return signingCert[0];
        }
        finally
        {
            store.Close();
        }
    }

Exception : Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'Access denied' 异常: Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException:'访问被拒绝'

Here is the stack: 这是堆栈:

        at System.Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle key, Byte[] input, AsymmetricPaddingMode paddingMode, Void* paddingInfo, EncryptOrDecryptAction encryptOrDecrypt)
        at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, EncryptOrDecryptAction encryptOrDecrypt)
        at System.Security.Cryptography.RSACng.Decrypt(Byte[] data, RSAEncryptionPadding padding)
        at VmeApi.Extensions.KeyEncryptService.DecryptKey(String key) in C:\Users\kevom\Source\Repos\VME\VME Management\Management Core Api\Extensions\AppSettings\KeyEncryptService.cs:line 69
        at VmeApi.Extensions.KeyEncryptService..ctor(String certName, String encryptedKey) in C:\Users\kevom\Source\Repos\VME\VME Management\Management Core Api\Extensions\AppSettings\KeyEncryptService.cs:line 31
        at Management_Core_Api.Startup.ConfigureServices(IServiceCollection services) in C:\Users\kevom\Source\Repos\VME\VME Management\Management Core Api\Startup.cs:line 83

I have tried giving my account, IUser Account and network service full access to the certificate's private key using mmc and restarting the OS but that didn't do anything. 我尝试使用mmc授予我的帐户,IUser帐户和网络服务对证书的私钥的完全访问权限,然后重新启动OS,但这无济于事。

This might be a bit long, so I will put it in as an answer, since the formatting as a comment might not be sufficient, 这可能有点长,所以我将其作为答案,因为作为注释的格式可能不够,

Try checking is the private key is accessible using the following code 尝试检查是否可以使用以下代码访问私钥

private static string FindKeyLocation(string keyFileName)
        {
            string firstLocation =
            Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
            string secondLocation = firstLocation + @"\Microsoft\Crypto\RSA\MachineKeys";
            string[] textArray1 = Directory.GetFiles(secondLocation, keyFileName);
            if (textArray1.Length > 0)
            {
                return secondLocation;
            }
            string thirdLocation =
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            string forthLocation = thirdLocation + @"\Microsoft\Crypto\RSA\";
            textArray1 = Directory.GetDirectories(forthLocation);
            if (textArray1.Length > 0)
            {
                foreach (string fifthLocation in textArray1)
                {
                    textArray1 = Directory.GetFiles(fifthLocation, keyFileName);
                    if (textArray1.Length != 0)
                    {
                        return fifthLocation;
                    }
                }
            }
            return "Private key exists but is not accessible";
        }

you would use the code in by specifying the certificate fileName as 您可以通过将证书fileName指定为来使用代码

RSACryptoServiceProvider rsa = cert.PrivateKey as RSACryptoServiceProvider;

            if (rsa != null)
            {
                string keyfilepath =
                    FindKeyLocation(rsa.CspKeyContainerInfo.UniqueKeyContainerName);
            }

This bit of code maybe can shed some light on why the decrypt might not work, the full method to add a user to a certificate in code would look something like this 这段代码也许可以阐明解密为什么不起作用的原因,将用户添加到证书中的完整方法看起来像这样

private static void AddAccessToCertificate(X509Certificate2 cert, string user)
        {
            RSACryptoServiceProvider rsa = cert.PrivateKey as RSACryptoServiceProvider;

            if (rsa != null)
            {
                string keyfilepath =
                    FindKeyLocation(rsa.CspKeyContainerInfo.UniqueKeyContainerName);

                FileInfo file = new FileInfo(keyfilepath + "\\" +
                    rsa.CspKeyContainerInfo.UniqueKeyContainerName);

                FileSecurity fs = file.GetAccessControl();

                NTAccount account = new NTAccount(user);
                fs.AddAccessRule(new FileSystemAccessRule(account,
                FileSystemRights.FullControl, AccessControlType.Allow));

                file.SetAccessControl(fs);
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM