1

I'm integrating a 3rd party API, where they want us to send some fields encrypted using their public key. I've seen RSACryptoServiceProvider and RSA class in dotnet but didn't find any way to put my public key explicitly.

What I want: string encryptedString Encrypt(string data, string publicKey, RSAEncryptionPadding.Pkcs1) { //code here. }

  • According to the link you posted, a public key can be imported with `ImportSubjectPublicKeyInfo` and `ImportRSAPublicKey` depending on the format of your key. Both methods expect a DER encoded key. – Topaco Dec 02 '20 at 18:52
  • What have you tried so far? Have you written any code that you can share? – DomBurf Dec 02 '20 at 19:59
  • One more note: A possible solution also depends on the .NET version used. Both methods posted in my last comment are available under .NET Core 3.x (and .NET 5.0). Under .NET Framework e.g. BouncyCastle offers comfortable possibilities. You should therefore post your .NET version and also the format of your public key, s. [here](https://stackoverflow.com/q/18039401/9014097). – Topaco Dec 02 '20 at 20:27
  • @Topaco Key Format: PEM File Version: Dot Net Core 2.1 – Tushar Goyal Dec 04 '20 at 05:27
  • @Topaco I just checked none of these methods are accessible in dot net core 2.1 – Tushar Goyal Dec 04 '20 at 05:34
  • @DomBurf public static string RSAEncrypt(string content) { RSAParameters parameters = new RSAParameters() { Modulus = Encoding.UTF8.GetBytes(""), Exponent = Encoding.UTF8.GetBytes("") }; RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(parameters); byte[] cipherbytes = rsa.Encrypt(Encoding.UTF8.GetBytes(content), false); return Convert.ToBase64String(cipherbytes); } – Tushar Goyal Dec 04 '20 at 05:38
  • As already mentioned, these methods are available as of .NET Core 3.x (neither in earlier .NET Core versions nor in the .NET Framework). – Topaco Dec 04 '20 at 07:58
  • In .NET Core 2.1 some required functionalities aren't available. So, I'd use BouncyCastle. The further way depends on the used key format, _so a more precise answer is only possible if you post the public key format_. PEM isn't the format, but the encoding. The format is usually X.509/SPKI (_BEGIN PUBLIC KEY_) or PKCS#1 (_BEGIN RSA PUBLIC KEY_), see the previously posted link. – Topaco Dec 04 '20 at 08:03
  • @Topaco public key format: -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAIIBCgKCAQEApYgxjOXNifbSTUlKTTda fVx75ipRYI7WhSnYaK0D6b3sIMz5KM82ApSpUQ2l4B/+jJJGkuTESNBHDlefd9no ZIAkCgY+0dSWdBejlIsYBAkXUcu9WRLO1mPPZQ8sLJxhOCPfJnh0HN8aJAP8QGzR S5aNKNlwZYyyJkUI+C29jfSqEy+qvuHwwEK4z9N/J5ZK4y+e6oX7TnRW1ZOCZDCo YnKK1KMWdBpfjWBNHdyVyRCYkcpfv1Y9kI103OSwtOQzqRFTGGZ54zuMIgEsPO2U +nutY9xexmgR70UFWPZWYxL03NpJSqv7duDu73g5YLJRukHbQ6adLp/gYWMH6uU 5 awIDAQAB -----END PUBLIC KEY----- – Tushar Goyal Dec 05 '20 at 18:39
  • According to header and footer this is a public key in _X.509/SPKI_ format. However, the key seems to be invalid or damaged, as you can easily verify with an ASN.1 parser, e.g. [online](https://lapo.it/asn1js/). In [_therightstuff/RSAKeys.cs_](https://gist.github.com/therightstuff/aa65356e95f8d0aae888e9f61aa29414) you can find a code that imports a public _X.509/SPKI_ key using _BouncyCastle_'s `PemReader` and also works under _.NET Core 2.1_, see `ImportPublicKey(string pem)`. Of course, a _valid_ key is required. – Topaco Dec 05 '20 at 21:41

1 Answers1

1

The following code is doing a complete round in RSA encryption & decryption with PKCS1 padding. As you can see I'm using hard coded keys in (dotnet) XML-format. As @Topaco already commented you can import the public key with other functions as well, depending on the key type.

As you probably get the public key in PEM-format ("-----BEGIN PUBLIC KEY-----...") you can use an online service like https://superdry.apphb.com/tools/online-rsa-key-converter to convert the PEM-key to a XML key (never ever do this with a private key!!).

This is the output of my sample program, you can run it in my live fiddle as well: 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

Security warning: the following code has no exception handling and is for educational purpose only.

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>";
  }

}
Michael Fehr
  • 5,827
  • 2
  • 19
  • 40
  • RSAalg.FromXmlString(publicKeyXml); This is giving me an error: "Operation not supported on this platform", I've used another method of feeding public key, (using RSAParameters), not a problem. – Tushar Goyal Dec 04 '20 at 07:55
  • I've extracted the modulus and exponent from https://superdry.apphb.com/tools/online-rsa-key-converter is there any better way to feed the public key? – Tushar Goyal Dec 04 '20 at 07:56
  • As already commented by @Topaco you can use an extern library like Bouncy Castle. – Michael Fehr Dec 04 '20 at 08:21