encryption - RSA解密抛出 'Access denied'异常

标签 encryption .net-core x509certificate .net-standard

我正在将一些 .NET Framework 库切换到 .NET Standard。我的一个库使用本地计算机上的证书存储来处理 JSON Web token (JWT)。该库正在使用 RSACryptoServiceProvider ,看起来是 not recommended不再了。

因此,我改用 GetPublicKey()GetPrivateKey() 扩展方法,但我遇到了私钥问题。每当我对收到的私钥的 RSA 实例调用 Decrypt 时:

{Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Access denied 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)

以下是导致异常的代码的简短示例:

public X509Certificate2 GetCert() {
    using (var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine)) {
        certStore.Open(OpenFlags.ReadOnly);
        var certMatches = certStore.Certificates.Find(X509FindType.FindByThumbprint, CertificateThumbprint, false);
        return certMatches[0];
    }
}

var cert = GetCert();
var publicKey = cert.GetRSAPublicKey();
var encryptedBytes = publicKey.Encrypt(bytes, System.Security.Cryptography.RSAEncryptionPadding.OaepSHA256);
var privateKey = cert.GetRSAPrivateKey();

// Exception on this line.  :(
var decryptedBytes = privateKey.Decrypt(encryptedBytes, System.Security.Cryptography.RSAEncryptionPadding.OaepSHA256);

使用RSACryptoServiceProvider可以使用相同的代码。我已验证用户有权访问商店中证书的私钥。

是什么原因导致此访问被拒绝异常?

最佳答案

问题似乎是,当创建(或导入)私钥时,它被标记为仅签名 key 。使用 CNG key ,可以(并且在本例中已经)通过检查 KeyUsages 来验证这一点。 CngKey的属性(property)对象(((RSACng)privateKey).Key.KeyUsages)。

在继续之前,请查看 RSACryptoServiceProvider您的 key 的版本。 rsaCsp.CspParameters.KeyNumber这就是我们真正寻找的。

switch (rsaCsp.CspParameters.KeyNumber)
{
    case 0:
       You're on the CAPI-to-CNG bridge, new to Windows 10.
       Keep going, this is the answer I answered.
       break;
    case 1:
       This is a CAPI AT_KEYEXCHANGE key.
       Things should just work...
       break;
    case 2:
       This is a CAPI AT_SIGNATURE key, I don't understand why CAPI allowed decryption.
       A different answer is required.
       break;
    default:
       throw new ArgumentOutOfRangeException();
}

从技术上讲, key “最终确定”后(CNG 术语,而不是 .NET 术语), key 用法就无法更改。但如果 key 是可导出的,您可以使用类似的方法解决问题

private static CngKey ResetKeyUsage(CngKey key)
{
    CngKeyCreationParameters keyParameters = new CngKeyCreationParameters
    {
        ExportPolicy = key.ExportPolicy,
        KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey,
    };

    if (key.IsMachineKey)
    {
        keyParameters.Parameters.Add(
            key.GetProperty("Security Descr", (CngPropertyOptions)4));

        keyParameters.KeyCreationOptions |= CngKeyCreationOptions.MachineKey;
    }

    CngKeyBlobFormat rsaPrivateBlob = new CngKeyBlobFormat("RSAPRIVATEBLOB");

    keyParameters.Parameters.Add(
        new CngProperty(
            rsaPrivateBlob.Format,
            key.Export(rsaPrivateBlob),
            CngPropertyOptions.Persist));

    CngAlgorithm alg = key.Algorithm;
    string name = key.KeyName;

    CngKey newKey = CngKey.Create(alg, name, keyParameters);
    key.Dispose();
    return newKey;
}

请注意,这实际上应该是一次性操作,因为它无疑会对任何打开的 key 句柄造成不良影响。

如果 ExportPolicy 表示它是可导出的,但不是 PlaintextExportable,则涉及更复杂的繁琐操作(并且通过直接 P/Invoking 可能会变得更容易完成)。

关于encryption - RSA解密抛出 'Access denied'异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51993985/

相关文章:

go - go - 如何使用证书存储中的证书并在 gin 框架中运行 TLS?

java - 检查一个随机选择的数字签名是否足以验证多个签名的文件?

android - 如何安全地将一些数据从服务器传输到安卓设备

c# - .Net Core 2.2/Kestrel/Swagger 禁用分块/编码

c# - 如何提高 .NET Core Web API 的性能?

c# - 如何在 C# Core 控制台应用程序中使用 MemoryCache?

wcf - 如何制作X.509证书?

java - PKCS#1 V2.0 是为 Java 实现的吗?

encryption - HSM解密+加密链

c# - 将 Simplemembership 创建的散列密码与 WPF 输入的密码匹配