无法在 .Net Core 中使用 RSA 私钥解密连接字符串

Posted

技术标签:

【中文标题】无法在 .Net Core 中使用 RSA 私钥解密连接字符串【英文标题】:Unable to decrypt connection string using RSA private key in .Net Core 【发布时间】:2020-01-23 06:17:03 【问题描述】:

我能够使用带有 Encoding.UTF8 和 RSACryptoServiceProvider() 的 RSA 公钥加密连接字符串。

但是当我试图解密它时,我正面临着

"System.InvalidOperationException: XML 文档 (1, 2) 中存在错误。 ---> System.InvalidOperationException:不是预期的。”

"ConnectionStrings": 
    "ConnectionString": "JLR+q4Bf3HyHpmby2gBI/bQi2C3Oqun+4lemvsBxeXU6YjHnNvdq0q54gf4VVbHDDkx5a57cGNgsSkYWP5uzJtsmdLQnJU5kA4yRSdaKbUdxE1aVDJMcJneVsNo73CSGhXQcK9zN8ILZeD/a51bA9ap00vWfx4v/nvCTZe3s26g="
  ;

public class HomeController : ControllerBase


    private ConnectionStrings connectionStrings  get; set; 


    public HomeController(IOptions<ConnectionStrings> settings)
    
        connectionStrings = settings.Value;
    


    public string Get()
    
        string data = connectionStrings.ConnectionString;

        string path = @"C:\temp\privateKey.xml";
        var privateKey = System.IO.File.ReadAllText(path);

        var bytesCypherText = Convert.FromBase64String(data);
        var csp = new RSACryptoServiceProvider();

        var sr = new System.IO.StringReader(privateKey);

        XmlSerializer xs = new XmlSerializer(typeof(RSAParameters));

        var privKey = (RSAParameters)xs.Deserialize(sr); // says error with the XML
        csp.ImportParameters(privKey);

        var plaintext = csp.Decrypt(bytesCypherText, false);
        return Encoding.Unicode.GetString(plaintext);
    


我正在使用 .NET CORE 框架,我遇到了很多 *** 线程,并且知道我们可以通过配置生成器来完成它,但我很难找到如何去做。

我是.Net平台的初学者,所以请验证以上细节并帮助我获取解密文本。

【问题讨论】:

为什么要对连接字符串进行 RSA 加密?这有点令人担忧。 需求从何而来? (你没有提到有这样的要求。) 这是我们项目计划的一部分,我们正在使用 RSA 这里应该使用 RSA 来完成什么? 为了完整起见:FromXmlString/ToXmlString 从 .NET Core 3.0 开始支持 (3.0, 3.1),here。在PlatformNotSupportedException 下方抛出。 IE。 csp.FromXmlString(privateKey); 也可以解决问题(假设对应的 .NET Core 版本)。 【参考方案1】:

您似乎正在尝试使用 RSA 解密密码(例如 ConnectionString)。

public static void Main()

    var privateKey= "<RSAKeyValue><Modulus>qltOYNlEOWNS4ACtgcIDzBkEyvJafolqakvAvtZeM9Vy6CK+ZD8mo0Xn1LkFXLMWjuCZBzXvaaaL8QQhT2iB1Kxas+nfQbgHhbRcNFisgaBRYiA5ilDuYPRoGXPDhuxysvjy/00CPpErdNqc/lSElpwNv0P5fwlwqPdZhBOxSL2WkRPkirSq06apACJ9UIP9d3lmgBkKJigGGDaJOjSotvtWZpONhnyr2ncHmREpaJd4O5hjxOESztMEHZf/LpoYsopEAVk+HAYbGf1J3MbzeL0nHupSGdVCG+YpJw0dHvujZEW4Q3+Ir4lGjDnntxcvffFUdH+cPsQuZyKD7fZ1rQ==</Modulus><Exponent>AQAB</Exponent><P>zNHC2XnpbcBr9iLf7Z3AoKD2SjgRcql4wwb/BeGFDFqRxS00T1tYd83AK2mBG1aqdyZH1idicTEM1TlW8FwhaO3kk0PoveBV5SVm537J8eG7MZ4yH0bKFYg8RjdkfrZppYHVCXE6ubEGTGOQGxTjjcUaLD9uqoorwPHKtOq8nY8=</P><Q>1Oz5iFxSnrZtUXcPcLAjoIQex3zDmgONyQEzVHndLHF6BO/9k6Dur2UiRfXQPltzEFfP8zZj1z+C7iuKfjnhOsRVour2A4gDduyezaHLb/4kCht2Sx8NB3wduAtsZr+8UmRJPeLvkEcN8+e0kG1oFHibUn7LiJv+RK/0wyeBEwM=</Q><DP>u7idH3nvChpMWQFJv5zQSeh9EzUkOLU+63DkF93Edbgk1lVCFmGgSd2X/bHrFMVv41iAirT6MshD/MFa/11RebxfvOGG1VBhKW4ITLAWIs1DJozZX3UgDnAY3joyrzg8x+ag/NB8hGjNXwH5t/iDPxKhlGBm64NL6sExinOCf90=</DP><DQ>rluHUrRXK4QzLHyUdjCmW/EUy0JNYjb6ydhj0g8goB4kTxq+yT8FdTcZw7Qw3H9CT+W4cW7efwqRCrs443g+CUNw5MIGxomAXMgSmkydLI4tsOEgEw/QOYrXQziHgfQMIGPi3fyRM9IbiNj6MTKGAg1pEzqlLK6gnlp/0bbtqUU=</DQ><InverseQ>G9FE60+miTihgULQbXu2xl6hCsdSUN7P5AtzxoZQYh5TNhytkMhDw7CXPnGaXLUCt5KUA8hax+kM9XbxP1fheRAe0llf1k7f6PEaWotposAbcS3GYjL2zZzRZTppsF3HO8/NTR6auYcDlz9f66kJqMYGnWMe/NrLKuRc4/rmbIQ=</InverseQ><D>Amgz3U50llL+8sdPrEuvfgzEcpGmEa+jX0keuhORVS4o53rGMehqhVgRhIHwv3SQVwh5YQ60CUwfIhKq3dJeM0EULwKY8vbEtHDt9JdkKJi5Taei6H9oPtp1Nhbapmdk336BAHZ4F6Y5dPc5zKYpEW+3CgLN3aumedy02RbmJF7zgJ1X7XDe2/TS8Xy7bXAQWyGryQt242VDskI8300d47Xqx4anwDgtXajNzpcVOkDS0/qjM92/CkHtAi8iL+XD83MuHtE4PdmtAVHQOjCBHCXWk6GwwmxO3dxPJtZq+um5+JhaEiekMTdoFTbh2OUfY870oBSu/XgAJ3nUyw/7SQ==</D></RSAKeyValue>";
    string connectionString = "NccK+nelOKXcLSd5kckt1jKQFu7nos1EpS8LITzjB8dO1R4anPoAkQlq4GD/cIJKznUVByJkzf4y8LfnufEVlpz0WsdCkxVkL65QlHL/HZzWXAyR9OJ1/Fveeu26aEJ7yMqGnX0EDmIckL9iY+DHyhKB3duCTcUnKfb7JTUbBmcdV2mkNQUxFgA1w6pSIq7gE7AG5JKPzfKfIvp+DPn3rYTY/DarsmeCwHFnWgV0WTQNzzh6c5retiCYPHwKXd4EzliwIvjhhfBOzsbszWV53vcE3talArnepShDCs9jjk3EUK0ptMp2CXbe7IyNeAgjNO9wTnp1dHNlrI9YLVZvuw==";
    var bytesCypherText = Convert.FromBase64String(connectionString);
    var csp = new RSACryptoServiceProvider();
    var rsaParam = ParseXmlString(privateKey);
    csp.ImportParameters(rsaParam);
    var bytesPlainTextData = csp.Decrypt(bytesCypherText, false);
    // Note The Encoding must be the SAME as how you convert string to bytes : 
    //    Here we use Unicode
    var plainText =  System.Text.Encoding.Unicode.GetBytes("hello,world");
    var x = csp.Encrypt(plainText, false);
    var plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
    Console.WriteLine(plainTextData);

这里的ParseXmlString(string xml) 主要是copied from GitHub

public static RSAParameters ParseXmlString( string xml)
    RSAParameters parameters = new RSAParameters();
    System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
    xmlDoc.LoadXml(xml);
    if (! xmlDoc.DocumentElement.Name.Equals("RSAKeyValue")) 
        throw new Exception("Invalid XML RSA key.");
    
    foreach (System.Xml.XmlNode node in xmlDoc.DocumentElement.ChildNodes)
    
        switch (node.Name)
        
            case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
            case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
            case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
            case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
            case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
            case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
            case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
            case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
        
    
    return parameters;

测试

一个测试上述代码的powershell:

$rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider -ArgumentList 2048
# export private key to xml
$rsa.ToXmlString($true) | Out-File key.private.xml

# plain 
$p =[System.Text.Encoding]::Unicode.GetBytes( "hello,world"); 
# cipher (bytes)
$c = $rsa.Encrypt($p, $false)
# cipher (base64)
$ct = [Convert]::ToBase64String($c)

#decrypted (bytes)
$d = $rsa.Decrypt($c, $false);
[System.Text.Encoding]::Unicode.GetString($d);

【讨论】:

以上是关于无法在 .Net Core 中使用 RSA 私钥解密连接字符串的主要内容,如果未能解决你的问题,请参考以下文章

Vue项目中的RSA加解密

理解RSA算法

ssh免口令密码登录及兼容性处理

RSA 私钥是不是始终包含公钥,还是只是 .NET?

Perl 和 .NET RSA 一起工作?从 Perl 公钥在 .NET 中加密?从 Perl 加载私钥?

在.NET中实现RSA公钥/私钥解密到Java/Spring