在 .Net Core 上使用非对称密钥

Posted

技术标签:

【中文标题】在 .Net Core 上使用非对称密钥【英文标题】:Using Asymmetric Key on .Net Core 【发布时间】:2018-07-25 06:43:17 【问题描述】:

我正在尝试运行此示例中的代码

https://docs.microsoft.com/en-us/dotnet/standard/security/how-to-store-asymmetric-keys-in-a-key-container

.NetCore 2.0(网络应用)下。

但是,当我尝试使用

执行任何行时
CspParameters

我收到以下错误

'CspParameters' requires Windows Cryptographic API (CAPI), which is not available on this platform.

请就我如何解决此问题提出建议。 谢谢。

【问题讨论】:

【参考方案1】:

.NET 不存储加密密钥,这最终是它所构建的加密平台提供(或不提供)的一项功能。

要将 CspParameters 与 .NET Core 一起使用,您必须在 Windows 上运行;因为这是对(旧)Windows Cryptographic API 的一个非常薄的包装器。您不能在 UAP 中使用它,因为 UAP 只允许更新的 Cryptography: Next Generation (CNG) API。

macOS 可以将密钥存储在 Keychain 中,但 .NET Core 不提供读取它们的 API。

Linux (OpenSSL) 除了“将其保存到文件并再次加载”之外没有任何密钥存储机制,但 .NET Core 不支持从文件加载非对称密钥。

在跨平台机制中实现目标的唯一方法是将非对称密钥与 X.509 证书相关联。如果您构建 HasPrivateKey 返回 true 的 X509Certificate2 对象,您可以将其保存到 PFX/PKCS#12 文件,然后从该文件加载;或者您可以将其添加到 X509Store 实例(CurrentUser 的“我的”存储是跨平台效果最好的存储),然后从 X509Store 实例中读取它。

尽管您引用的页面声称是 2017 年编写的,但其真正含义是该内容已从该日期在 msdn.microsoft.com 上的先前位置移动。原始页面写于 2008 年(至少,这是 web.archive.org 上的第一次点击),所以它早于 .NET Core。

【讨论】:

【参考方案2】:

您现在可以跨平台执行此操作,只要您使用 .netcore 3.0 或更高版本并添加最新的 System.Security.Cryptography.Cng nuget 包(注意!这个仅当您的项目不是多目标时才有效 - 它只能针对 netcoreapp3.0):

using (ECDsa key = ECDsa.Create())
            
                key.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _);

                return Jose.JWT.Encode
                    (
                    payload: payload,
                    key: key,
                    algorithm: JwsAlgorithm.ES256,
                    extraHeaders: extraHeader
                    );
            

【讨论】:

【参考方案3】:

所以只是想提供另一个我们在遇到此错误时发现的选项。该 CSP 参数错误与 RSACryptoServiceProvider 有关。这与跨平台 .NET Core 存在一些问题。我们找到了一个 Github issue,它提到要使用 RSA.Create() 方法。我正在使用仍然使用 RSACryptoServiceProvider 的 Bouncy Castle library。在撰写此答案时,它看起来像这样。

        public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
    
        RSAParameters rp = ToRSAParameters(privKey);
        RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
        rsaCsp.ImportParameters(rp);
        return rsaCsp;
     

所以我们只是用类中的私有方法替换它,看起来像这样。

            private RSA ToRSA(RsaPrivateCrtKeyParameters parameters)
        
            RSAParameters rp = DotNetUtilities.ToRSAParameters(parameters);
            return RSA.Create(rp);
        

这在 linux 中运行,没有错误。 Bouncy 可能只需要更新他们的库。

【讨论】:

【参考方案4】:

使用此方法从密钥字符串导入公钥确保安装 BouncyCastle.NetCore nuget 包

  public static RSACryptoServiceProvider ImportPublicKey(string pem)
    
        PemReader pr = new PemReader(new StringReader(pem));
        AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject();
        RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKey);

        RSACryptoServiceProvider csp = new RSACryptoServiceProvider();// cspParams);
        csp.ImportParameters(rsaParams);
        return csp;
    

然后您可以如下所示加密您的数据

 public static string Encryption(string data,string publickey)
    
        var testData = Encoding.GetEncoding("iso-8859-1").GetBytes(strText);

        using (var rsa = ImportPublicKey(publickey))
        
            try
            
                var encryptedData = rsa.Encrypt(testData, false);
                var base64Encrypted = Convert.ToBase64String(encryptedData);
                return base64Encrypted;
            
            finally
            
                rsa.PersistKeyInCsp = false;
            
        
    

【讨论】:

我已经尝试过这个解决方案,但这会在这一行产生异常: var encryptedData = rsa.Encrypt(testData, false); Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException:“错误长度” 增加密钥长度大小可能使用密钥大小超过 4096 的公钥

以上是关于在 .Net Core 上使用非对称密钥的主要内容,如果未能解决你的问题,请参考以下文章

非对称加密和对称加密

对称加密和非对称加密的区别

网络安全-非对称加密

JWT 密钥 - 非对称和对称

区块链中的非对称加密技术

区块链中的非对称加密技术