dotnet c#中的公钥RSA加密

Posted

技术标签:

【中文标题】dotnet c#中的公钥RSA加密【英文标题】:public key RSA encrption in dotnet c# 【发布时间】:2021-03-14 18:23:41 【问题描述】:

我正在集成一个第 3 方 API,他们希望我们在其中发送一些使用他们的公钥加密的字段。 我在 dotnet 中看到了RSACryptoServiceProvider 和 RSA 类,但没有找到任何方法来明确放置我的公钥。

我想要什么: string encryptedString Encrypt(string data, string publicKey, RSAEncryptionPadding.Pkcs1) //code here.

【问题讨论】:

根据您发布的链接,可以使用ImportSubjectPublicKeyInfoImportRSAPublicKey 导入公钥,具体取决于您的密钥格式。两种方法都需要一个 DER 编码的密钥。 到目前为止您尝试过什么?你写过代码可以分享吗? 另一个注意事项:可能的解决方案还取决于所使用的 .NET 版本。我上一条评论中发布的两种方法都可以在 .NET Core 3.x(和 .NET 5.0)下使用。在 .NET 框架下,例如BouncyCastle 提供舒适的可能性。因此,您应该发布您的 .NET 版本以及您的公钥 s 的格式。 here. @Topaco 密钥格式:PEM 文件版本:Dot Net Core 2.1 @Topaco 我刚刚检查了这些方法都不能在 dot net core 2.1 中访问 【参考方案1】:

以下代码使用 PKCS1 填充在 RSA 加密和解密中进行了完整的一轮。如您所见,我使用的是(dotnet)XML 格式的硬编码键。正如@Topaco 已经评论的那样,您也可以使用其他功能导入公钥,具体取决于密钥类型。

由于您可能获得 PEM 格式的公钥(“-----BEGIN PUBLIC KEY-----...”),因此您可以使用 https://superdry.apphb.com/tools/online-rsa-key-converter 等在线服务来转换 PEM 密钥到 XML 密钥(永远不要用私钥这样做!!)。

这是我的示例程序的输出,你也可以在我的 live fiddle 中运行它: https://dotnetfiddle.net/1LyKFB

RSA 2048 encryption PKCS1 string
plaintext: The quick brown fox jumps over the lazy dog

* * * encrypt the plaintext with the RSA public key * * *
ciphertextBase64: 7S7u+43NwYNV6041R0FlLMGvcJ/fRLPs4KQunUpa09XMk09Hzmzi6f0PYsoo5Bi8Y+kxYq0ocg+5BRCwyXV8MiH07ABzpGN9dDiijH16o5SJbDqN+8wC6PDJXirSY/8xj+4CPMbM4uFZI0wuWUGc5VchQ7UhgOg0fGo2nU3i2+UvDk9MSaU7V9GxfqHt03T92D0O7alXcak+Zm4khnzyONDzl9atlRdH5Gvm+BKy6Pi5ntoJj7BWcIhHF9qyKpUOkhN8shC3gGj/XpWfQpXs/inPXyR0DjrbtJ6MLIG+ScgCIMTB90L6L/r8pR0I1JJ0jAl+DR3U0V1DX7xPsV+utA==

* * * decrypt the ciphertext with the RSA private key * * *
ciphertextReceivedBase64: 7S7u+43NwYNV6041R0FlLMGvcJ/fRLPs4KQunUpa09XMk09Hzmzi6f0PYsoo5Bi8Y+kxYq0ocg+5BRCwyXV8MiH07ABzpGN9dDiijH16o5SJbDqN+8wC6PDJXirSY/8xj+4CPMbM4uFZI0wuWUGc5VchQ7UhgOg0fGo2nU3i2+UvDk9MSaU7V9GxfqHt03T92D0O7alXcak+Zm4khnzyONDzl9atlRdH5Gvm+BKy6Pi5ntoJj7BWcIhHF9qyKpUOkhN8shC3gGj/XpWfQpXs/inPXyR0DjrbtJ6MLIG+ScgCIMTB90L6L/r8pR0I1JJ0jAl+DR3U0V1DX7xPsV+utA==
decryptedData: The quick brown fox jumps over the lazy dog

安全警告:以下代码没有异常处理,仅用于教育目的。

using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;

public class RsaEncryptionOaepSha1 
    public static void Main() 
    Console.WriteLine("RSA 2048 encryption PKCS1 string");
    string dataToEncryptString = "The quick brown fox jumps over the lazy dog";
    Console.WriteLine("plaintext: " + dataToEncryptString);

    // # # # usually we would load the private and public key from a file or keystore # # #
    // # # # here we use hardcoded keys for demonstration - don't do this in real programs # # #
    string filenamePrivateKeyXml = "privatekey2048.xml";
    string filenamePublicKeyXml = "publickey2048.xml";

        try 
      // encryption
        Console.WriteLine("\n* * * encrypt the plaintext with the RSA public key * * *");
        string publicKeyLoad = loadRsaPublicKeyPem();
        // use this in production
        //string publicKeyLoad = File.ReadAllText(filenamePublicKeyXml);
        byte[] dataToEncrypt = Encoding.UTF8.GetBytes(dataToEncryptString);
        string ciphertextBase64 = Base64Encoding(rsaEncryptionPkcs1(publicKeyLoad, dataToEncrypt));
        //string ciphertextBase64 = "";
        Console.WriteLine("ciphertextBase64: " + ciphertextBase64);

        // transport the encrypted data to recipient

        // receiving the encrypted data, decryption
        Console.WriteLine("\n* * * decrypt the ciphertext with the RSA private key * * *");
        string ciphertextReceivedBase64 = ciphertextBase64;
        Console.WriteLine("ciphertextReceivedBase64: " + ciphertextReceivedBase64);
        string privateKeyLoad = loadRsaPrivateKeyPem();
        // use this in production
        //string privateKeyLoad = File.ReadAllText(filenamePrivateKeyXml);
        byte[] ciphertextReceived = Base64Decoding(ciphertextReceivedBase64);
        byte[] decryptedtextByte = rsaDecryptionPkcs1(privateKeyLoad, ciphertextReceived);
        Console.WriteLine("decryptedData: " + Encoding.UTF8.GetString(decryptedtextByte, 0, decryptedtextByte.Length));
        
        catch(ArgumentNullException) 
            Console.WriteLine("The data was not RSA encrypted");
        
    

  public static byte[] rsaEncryptionPkcs1(string publicKeyXml, byte[] plaintext) 
    RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider(2048);
        RSAalg.PersistKeyInCsp = false;
        RSAalg.FromXmlString(publicKeyXml);
        return RSAalg.Encrypt(plaintext, false);
  

  public static byte[] rsaDecryptionPkcs1(string privateKeyXml, byte[] ciphertext) 
    RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider(2048);
        RSAalg.PersistKeyInCsp = false;
        RSAalg.FromXmlString(privateKeyXml);
    return RSAalg.Decrypt(ciphertext, false);
  

  static string Base64Encoding(byte[] input) 
    return Convert.ToBase64String(input);
  

  static byte[] Base64Decoding(String input) 
    return Convert.FromBase64String(input);
  

  public static string loadRsaPublicKeyPem() 
    return "<RSAKeyValue><Modulus>8EmWJUZ/Osz4vXtUU2S+0M4BP9+s423gjMjoX+qP1iCnlcRcFWxthQGN2CWSMZwR/vY9V0un/nsIxhZSWOH9iKzqUtZD4jt35jqOTeJ3PCSr48JirVDNLet7hRT37Ovfu5iieMN7ZNpkjeIG/CfT/QQl7R+kO/EnTmL3QjLKQNV/HhEbHS2/44x7PPoHqSqkOvl8GW0qtL39gTLWgAe801/w5PmcQ38CKG0oT2gdJmJqIxNmAEHkatYGHcMDtXRBpOhOSdraFj6SmPyHEmLBishaq7Jm8NPPNK9QcEQ3q+ERa5M6eM72PpF93g2p5cjKgyzzfoIV09Zb/LJ2aW2gQw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
  

  public static string loadRsaPrivateKeyPem() 
    return "<RSAKeyValue><Modulus>8EmWJUZ/Osz4vXtUU2S+0M4BP9+s423gjMjoX+qP1iCnlcRcFWxthQGN2CWSMZwR/vY9V0un/nsIxhZSWOH9iKzqUtZD4jt35jqOTeJ3PCSr48JirVDNLet7hRT37Ovfu5iieMN7ZNpkjeIG/CfT/QQl7R+kO/EnTmL3QjLKQNV/HhEbHS2/44x7PPoHqSqkOvl8GW0qtL39gTLWgAe801/w5PmcQ38CKG0oT2gdJmJqIxNmAEHkatYGHcMDtXRBpOhOSdraFj6SmPyHEmLBishaq7Jm8NPPNK9QcEQ3q+ERa5M6eM72PpF93g2p5cjKgyzzfoIV09Zb/LJ2aW2gQw==</Modulus><Exponent>AQAB</Exponent><P>/8atV5DmNxFrxF1PODDjdJPNb9pzNrDF03TiFBZWS4Q+2JazyLGjZzhg5Vv9RJ7VcIjPAbMy2Cy5BUffEFE+8ryKVWfdpPxpPYOwHCJSw4Bqqdj0Pmp/xw928ebrnUoCzdkUqYYpRWx0T7YVRoA9RiBfQiVHhuJBSDPYJPoP34k=</P><Q>8H9wLE5L8raUn4NYYRuUVMa+1k4Q1N3XBixm5cccc/Ja4LVvrnWqmFOmfFgpVd8BcTGaPSsqfA4j/oEQp7tmjZqggVFqiM2mJ2YEv18cY/5kiDUVYR7VWSkpqVOkgiX3lK3UkIngnVMGGFnoIBlfBFF9uo02rZpC5o5zebaDIms=</Q><DP>BPXecL9Pp6u/0kwY+DcCgkVHi67J4zqka4htxgP04nwLF/o8PF0tlRfj0S7qh4UpEIimsxq9lrGvWOne6psYxG5hpGxiQQvgIqBGLxV/U2lPKEIb4oYAOmUTYnefBCrmSQW3v93pOP50dwNKAFcGWTDRiB/e9j+3EmZm/7iVzDk=</DP><DQ>rBWkAC/uLDf01Ma5AJMpahfkCZhGdupdp68x2YzFkTmDSXLJ/P15GhIQ+Lxkp2swrvwdL1OpzKaZnsxfTIXNddmEq8PEBSuRjnNzRjQaLnqjGMtTBvF3G5tWkjClb/MW2q4fgWUG8cusetQqQn2k/YQKAOh2jXXqFOstOZQc9Q0=</DQ><InverseQ>BtiIiTnpBkd6hkqJnHLh6JxBLSxUopFvbhlR37Thw1JN94i65dmtgnjwluvR/OMgzcR8e8uCH2sBn5od78vzgiDXsqITF76rJgeO639ILTA4MO3Mz+O2umrJhrkmgSk8hpRKA+5Mf9aE7dwOzHrc8hbj8J102zyYJIE6pOehrGE=</InverseQ><D>hXGYfOMFzXX/vds8HYQZpISDlSF3NmbTCdyZkIsHjndcGoSOTyeEOxV93MggxIRUSjAeKNjPVzikyr2ixdHbp4fAKnjsAjvcfnOOjBp09WW4QCi3/GCfUh0w39uhRGZKPjiqIj8NzBitN06LaoYD6MPg/CtSXiezGIlFn/Hs+MuEzNFu8PFDj9DhOFhfCgQaIgEEr+IHdnl5HuUVrwTnIBrEzZA/08Q0Gv86qQZctZWoD9hPGzeAC+RSMyGVJw6Ls8zBFf0eysB4spsu4LUom/WnZMdS1ls4eqsAX+7AdqPKBRuUVpr8FNyRM3s8pJUiGns6KFsPThtJGuH6c6KVwQ==</D></RSAKeyValue>";
  


【讨论】:

RSAalg.FromXmlString(publicKeyXml);这给了我一个错误:“此平台不支持操作”,我使用了另一种提供公钥的方法(使用 RSAParameters),没问题。 我已经从superdry.apphb.com/tools/online-rsa-key-converter 中提取了模数和指数,有没有更好的方法来提供公钥? 正如@Topaco 已经评论的那样,您可以使用像 Bouncy Castle 这样的外部库。

以上是关于dotnet c#中的公钥RSA加密的主要内容,如果未能解决你的问题,请参考以下文章

C# RSA 加密/解密与传输

(转)C#实现RSA非对称加密解密

C# 与JAVA 的RSA 加密解密交互,互通,C#使用BouncyCastle来实现私钥加密,公钥解密的方法

RSA 加密 C#

C# RSA加密算法PEM格式转换XML

C# RSA加密算法PEM格式转换XML