【问题标题】:Decrypt encrypted key using Certificate not working in .NET but works in SOAP UI使用证书解密加密密钥在 .NET 中不起作用但在 SOAP UI 中起作用
【发布时间】:2018-09-26 12:20:48
【问题描述】:

我试图弄清楚为什么我似乎无法使用 X509 证书从 .NET 解密加密密钥。

    encryptedKey = "jW3VDsUZWIdzfZ1bPN3iKI2Pf9u22kUax0DFnF3A9H+nvcBQuVC2efw1FYGm5/AvnN27kXqA4PyCqcQLp/tguVqHtzdR7mJtkTCyY8TUoAej2Mqzv2uiEKULB/8rlPDl2DOkSMGJqieenAG/7gZjWhlU0eYrlcMi5dtAnPFTfy+LvtJ6bbGEDgy4FhoT49T6sO0kjBJHp5YI0p/CeEuc+WMT/BMGG1YuDPswltj0VzeaE3KbHSLvJPjGCQ3U0YkUWm8h9zM22S/mRvfMhEu1aRdQpojGUiSLKUJyotNu8fRulKeB1TVuE7AlDGrbAUsRtU+y6PdLMcEHW+BRq5Uouw==";

    var encryptedKeyByte = Convert.FromBase64String(encryptedKey);

    var clientCert = new X509Certificate2(@"C:\certificates\xxxxx.pfx", "xxxx");
    var rsa = (RSACryptoServiceProvider)clientCert.PrivateKey;
    byte[] key = rsa.Decrypt(encryptedKeyByte, false);

当我尝试运行代码的最后一行rsa.Decrypt(encryptedKeyByte, false)时出现的错误

参数不正确。

在 SOAP UI 中,我使用相同的证书进行解密。我只需要将文件 pfx 转换为 jks 文件即可使其在 SOAP UI 中工作。但除此之外,设置对我来说是一样的。 这是 SOAP UI 设置的屏幕截图。我猜 SOAP UI 设置中的签名密钥库不用于解密过程。 SOAP UI 中的解密密钥库设置是我在 .NET 中使用的设置。只有在 .NET 中它是一个 pfx 文件。

这是来自 MMC 的证书详细信息

堆栈跟踪错误:

服务器堆栈跟踪:

   at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
   at System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean fOAEP, ObjectHandleOnStack ohRetDecryptedKey)
   at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
   at Microsoft.Austria.WcfHelpers.SoapWithAttachments.SwaEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders, String contentType) in C:\Crap\Stuff\CARES\Microsoft.Austria.WcfHelpers.SoapWithAttachments\SwaEncoder.cs:line 503
   at Microsoft.Austria.WcfHelpers.SoapWithAttachments.SwaEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders, String contentType) in C:\Crap\Stuff\CARES\Microsoft.Austria.WcfHelpers.SoapWithAttachments\SwaEncoder.cs:line 458
   at Microsoft.Austria.WcfHelpers.SoapWithAttachments.SwaEncoder.ReadMessage(ArraySegment`1 buffer, BufferManager bufferManager, String contentType) in C:\Crap\Stuff\CARES\Microsoft.Austria.WcfHelpers.SoapWithAttachments\SwaEncoder.cs:line 126
   at System.ServiceModel.Channels.HttpInput.DecodeBufferedMessage(ArraySegment`1 buffer, Stream inputStream)
   at System.ServiceModel.Channels.HttpInput.ReadBufferedMessage(Stream inputStream)
   at System.ServiceModel.Channels.HttpInput.ParseIncomingMessage(HttpRequestMessage httpRequestMessage, Exception& requestException)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 

【问题讨论】:

  • 我假设 encryptedKey 是你要解密的值?
  • 是的。作为步骤 1。然后用它来解密正文。目前我什至无法通过第一步。
  • 请问引发异常的类型是什么?
  • 但是什么类型?例如CryptpgraphicException, ArgumentOutOfRangeException, InvalidOperationException ?
  • 那么最后一次检查 - 你能查询属性 clientCert.HasPrivateKey 并报告它是真还是假。如果为真,那么我所能想到的就是 encryptedKey 值是使用不同证书加密的结果。如果为 false,则证书不包含用于尝试解密的私钥。

标签: c# encryption soap cryptography


【解决方案1】:

这门课可能对你有帮助吗:

public class TFRSAEncryption
{
    public string RsaEncryptWithPublic(string clearText, string publicKey)
    {
        var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);

        var encryptEngine = new Pkcs1Encoding(new RsaEngine());

        using (var txtreader = new StringReader(publicKey))
        {
            var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();

            encryptEngine.Init(true, keyParameter);
        }

        var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
        return encrypted;

    }

    public string RsaEncryptWithPrivate(string clearText, string privateKey)
    {
        var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);

        var encryptEngine = new Pkcs1Encoding(new RsaEngine());

        using (var txtreader = new StringReader(privateKey))
        {
            var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();

            encryptEngine.Init(true, keyPair.Private);
        }

        var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
        return encrypted;
    }


    // Decryption: 

    public string RsaDecryptWithPrivate(string base64Input, string privateKey)
    {
        var bytesToDecrypt = Convert.FromBase64String(base64Input);

        AsymmetricCipherKeyPair keyPair;
        var decryptEngine = new Pkcs1Encoding(new RsaEngine());

        using (var txtreader = new StringReader(privateKey))
        {
            keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();

            decryptEngine.Init(false, keyPair.Private);
        }

        var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
        return decrypted;
    }

    public string RsaDecryptWithPublic(string base64Input, string publicKey)
    {
        var bytesToDecrypt = Convert.FromBase64String(base64Input);

        var decryptEngine = new Pkcs1Encoding(new RsaEngine());

        using (var txtreader = new StringReader(publicKey))
        {
            var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();

            decryptEngine.Init(false, keyParameter);
        }

        var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
        return decrypted;
    }
}

【讨论】:

    【解决方案2】:

    该错误使我相信加密数据无法使用指定的方法解密。您可以在专门使用 .GetRSAPrivateKey() 的地方尝试这种方式,然后使用正确的填充方法进行解密。

    据我所知,没有办法知道正在使用哪种填充方法,但您可以遍历选项并查看是否适合您。

    var certPath = @"c:\code\temp\xxxxxxxxx.pfx";
    var cert = new X509Certificate2(certPath, "xxxxxxx");
    var decryptedData = cert.GetRSAPrivateKey().Decrypt(encryptedByteInfo, RSAEncryptionPadding.OaepSHA1);
    

    本文列出填充方法:https://msdn.microsoft.com/en-us/library/system.security.cryptography.rsaencryptionpadding(v=vs.110).aspx

    【讨论】:

    • 您从哪里获得 GetRSAPrivateKey?该方法不存在。
    • 您使用的是什么版本的 .NET?
    • VS 2015。不使用 .NET Core。你一定在用那个。 2015 年你有解决方案吗?
    • 谢谢。你为什么认为它的填充问题?
    • 该错误表明加密的数据不是预期的格式。当我在 .NET 4.6 中使用自己的实现时,填充是一种简单的方法,我可以“破坏”使其在一个实例而不是另一个实例中工作的东西。
    猜你喜欢
    • 1970-01-01
    • 2016-07-10
    • 2016-11-07
    • 2017-03-25
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多