RSA encrypt in Delphi and decrypt in .NET

Dear TMS team,


can you please give me a hint how to encrypt a string in Delphi with RSA algorithm using the TMS Cryptography Pack and decrypt it with the RSACryptoServiceProvider in .NET? Currently all my tests have failed :-(

Thank you!

Regards,
Maik
Hi Maik,

Could you give us some code to test in .NET? And your code in Delphi using the TMS Crypto Pack?

Best regards,
Marion

Dear Marion,


Thank you very for your very quick answer.


I first found out that I have to create the RSA parameters in .NET as there are additional fields needed in the RSACryptoServiceProvider to generate an object with an existing RSA key. Please have a look at the following code generating the 2048 bits key parameters and exporting it to the console.


public static void GenerateKeyString()

{

    var cryptoServiceProvider = new RSACryptoServiceProvider(2048);


    var rsaParameters = cryptoServiceProvider.ExportParameters(true);


    var stringWriter = new System.IO.StringWriter();

    var xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));


    xmlSerializer.Serialize(stringWriter, rsaParameters);


    Console.WriteLine(stringWriter.ToString());

}


Executing the console application will give me the following XML representation of the RSA key parameters.


<?xml version="1.0" encoding="utf-16"?>

<RSAParameters xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <Exponent>AQAB</Exponent>

  <Modulus>uzbtMdjXwkhvggQctl7TLg/YkM1UxHLqtj8zcntD/O/M+T/gCpMYRFjgHaM9+c1PwCFkG5yBw5VB0nxKUjoAnSo1K9PgGSHWUk4WRXtNrIRkUITQGQsU3GPLDHDzbu0w4+1v/UGE7POK5i3f64g70VdtwjQ3v7pa2soTWd/Mgah7WO33lJKC8RgM9HDo54874YFnFT+vgfP5wRYNHTb3UEITS/+qE4xooZtR0vzgWXymkb1f4MPFh5pm5S9dnAI5qRI2iqowYdpUitZAnnOPfR2lmQLeyH4D2wX6GycgnzFK5N6994jQl+Dn/qy8UbNUP647z5cl8KLfYtNZCg46ZQ==</Modulus>

  <P>4mF96uxly2vdKzwDdIGpe4rWzvSk9v/hu5shAoyy7CF0Cimjo+0irOaQOzZNfczp8ipjtQJoFFm/PovSr+sOn00V58bVTcf9YZZf7yDmWAYTO3rQPY9wc0oIm0q8ncpdhg3dkNqMuxg9Vzl5Y/G/foty9zcv3Ph2FVkc+ATOfRs=</P>

  <Q>07WUrxYBow0Blwpa4f5xi75z1bASQhrz+8qmQgX2JwUPyhQ7Ayt8snLDpngpuuvmtGZ7j3SaS0Ce+Y1rrlyb8rzqdijqOrwwpuGlrIHl79vwCkoUmb6Xmw+Grx5kCRwCwHW1nnvBDoPDIJyo+uHdsoBXcfRJRmOiGHPomUcvHn8=</Q>

  <DP>WRvxGbkF9MW3oF4WKhUj5opnNb2c9dERROyyWLOTdllQuPNdA5jDbnWvTm94n006xWUkLEsPNvuAyRj2zOJkthX8ymg87EoNlg1AI/u6T+nMRjx4ndLJe8gnjSElD6Npnuv0TCGLBdZrxtrLyqiNLT2s+lzRzVRL/uk9+u7BbQM=</DP>

  <DQ>uHYH/J3CA107u2yMT0ixij8BEnj9D5gIaaTiQ7iKBumEHmCOIm7rkVgpXIxqX7FXLGv20MGaBmNhoLI11pBeWJt99kIkA9Ug1ubYwXvU6q7JcU2msWa9FZ/ri/2Az+cWBrcI7fOJ/KmVhH67RQ0za2ojxuhASBJbk866JYM+bOU=</DQ>

  <InverseQ>O0mybCngn3qkItEfCxwOT0ayyye+ygJxZJ0sU9SncCfcREf/ecWAfpDjQNSUmOFph+JBUMkrgGYtGja7Ht976VW5m66pgAXUmIouAlO/R+J4cNHMGWUW42xrYfTxhYnsY5Yfbijy4O685lR/c1iXeg8ArGFblblniQEjLs7Tbb4=</InverseQ>

  <D>Km9lzmGvbjtLAzZ5Z6EQzyUKWrAgIbNGnm6u86kbHQ8h7/FZkCwNWRioHC+vUZsHE6696UBNbY68b8B6fC7nirhRexC4gBnaYaePhspPLeaIcnPYU4TegqIgGT7U/vTGmzNrqgUa4zbE6i3FzrZ/kJD3sQhzBoNwKp2ZS0reKRkrJyVZDVO0fRfHZLOS+d4uOb5XzngwFmmWcunlrPpCmG+mDUbQTR5Dd12x/qVI/LNgANJXdl4/A0ob9WA4D98agITkCyFbUXTHfZBLhTtCkNammAcCfPCV6HWFl52+I3VFP+SHfOZLS/Zwlc/fJ0BPVGi0izy+KvtRC3qsZtmPlQ==</D>

</RSAParameters>


In my opinion the <Modulus> element contains the RSA modulus in Base64 encoding, the <Exponent> element contains the RSA public exponent in Base64 encoding and the <D> element contains the RSA private exponent in Base64 encoding.


Now I am using the modulus and private exponent in Delphi to construct a RSA object and encrypt a string.


uses

  System.SysUtils, RSAObj, MiscObj;


procedure Encrypt(Value: string);

var

  RSA: TRSAEncSign;

begin

  RSA := TRSAEncSign.Create;


  RSA.keyLength := kl2048;

  RSA.encType := oaep;

  RSA.outputFormat := base64;


  RSA.modulus := 'uzbtMdjXwkhvggQctl7TLg/YkM1UxHLqtj8zcntD/O/M+T/gCpMYRFjgHaM9+c1PwCFkG5yBw5VB0nxKUjoAnSo1K9PgGSHWUk4WRXtNrIRkUITQGQsU3GPLDHDzbu0w' +

                 '4+1v/UGE7POK5i3f64g70VdtwjQ3v7pa2soTWd/Mgah7WO33lJKC8RgM9HDo54874YFnFT+vgfP5wRYNHTb3UEITS/+qE4xooZtR0vzgWXymkb1f4MPFh5pm5S9dnAI5' +

                 'qRI2iqowYdpUitZAnnOPfR2lmQLeyH4D2wX6GycgnzFK5N6994jQl+Dn/qy8UbNUP647z5cl8KLfYtNZCg46ZQ==';


  RSA.PublicExponent := 'AQAB';


  WriteLn(RSA.Encrypt(Value));

end;


begin

  try

    Encrypt('Test');

  except

    on E: Exception do

      Writeln(E.ClassName, ': ', E.Message);

  end;


  Readln;

end.


This will output the following cipher text for ?Test? in Base64 encoding on the console.


WFySQ7+NYeNhwW7k6ULiekuN6fTqpEqoMh7P5L2Ap+oE4NphkXj9sleFKLpHgHBVSCCzAgWL8uhaXu/jCR4tv/146wtucWCIqupya38K9ybz3PE48Dwk6y4bn6KleLDqvhs8SXNaV1k/s0b8zveumWspB85F96SBiZlwGxBbSX63mdIRdTX064xGY4G6EmeayvzHp2iSf7kimYzu9X3R/2gBW7ppbzl8CcS3sGZkrxgBfpZPvFdKsAY8vbXNuwXhDwSunyvPWJR+Mq0g70kU2ckSIJ/lA5MtabCYNN4o1kl3oHEcS6Y2Y2pQIM5xkVGuTBnXAA7JI6Lrj/U3jfNqMw==

In .NET I do the same encryption with the generate key like in the following code snippet.


private static void Encrypt(string value)

{

    var cryptoServiceProvider = new RSACryptoServiceProvider(2048);

    

    cryptoServiceProvider.FromXmlString("<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RSAParameters xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n  <Exponent>AQAB</Exponent>\r\n  <Modulus>uzbtMdjXwkhvggQctl7TLg/YkM1UxHLqtj8zcntD/O/M+T/gCpMYRFjgHaM9+c1PwCFkG5yBw5VB0nxKUjoAnSo1K9PgGSHWUk4WRXtNrIRkUITQGQsU3GPLDHDzbu0w4+1v/UGE7POK5i3f64g70VdtwjQ3v7pa2soTWd/Mgah7WO33lJKC8RgM9HDo54874YFnFT+vgfP5wRYNHTb3UEITS/+qE4xooZtR0vzgWXymkb1f4MPFh5pm5S9dnAI5qRI2iqowYdpUitZAnnOPfR2lmQLeyH4D2wX6GycgnzFK5N6994jQl+Dn/qy8UbNUP647z5cl8KLfYtNZCg46ZQ==</Modulus>\r\n  <P>4mF96uxly2vdKzwDdIGpe4rWzvSk9v/hu5shAoyy7CF0Cimjo+0irOaQOzZNfczp8ipjtQJoFFm/PovSr+sOn00V58bVTcf9YZZf7yDmWAYTO3rQPY9wc0oIm0q8ncpdhg3dkNqMuxg9Vzl5Y/G/foty9zcv3Ph2FVkc+ATOfRs=</P>\r\n  <Q>07WUrxYBow0Blwpa4f5xi75z1bASQhrz+8qmQgX2JwUPyhQ7Ayt8snLDpngpuuvmtGZ7j3SaS0Ce+Y1rrlyb8rzqdijqOrwwpuGlrIHl79vwCkoUmb6Xmw+Grx5kCRwCwHW1nnvBDoPDIJyo+uHdsoBXcfRJRmOiGHPomUcvHn8=</Q>\r\n  <DP>WRvxGbkF9MW3oF4WKhUj5opnNb2c9dERROyyWLOTdllQuPNdA5jDbnWvTm94n006xWUkLEsPNvuAyRj2zOJkthX8ymg87EoNlg1AI/u6T+nMRjx4ndLJe8gnjSElD6Npnuv0TCGLBdZrxtrLyqiNLT2s+lzRzVRL/uk9+u7BbQM=</DP>\r\n  <DQ>uHYH/J3CA107u2yMT0ixij8BEnj9D5gIaaTiQ7iKBumEHmCOIm7rkVgpXIxqX7FXLGv20MGaBmNhoLI11pBeWJt99kIkA9Ug1ubYwXvU6q7JcU2msWa9FZ/ri/2Az+cWBrcI7fOJ/KmVhH67RQ0za2ojxuhASBJbk866JYM+bOU=</DQ>\r\n  <InverseQ>O0mybCngn3qkItEfCxwOT0ayyye+ygJxZJ0sU9SncCfcREf/ecWAfpDjQNSUmOFph+JBUMkrgGYtGja7Ht976VW5m66pgAXUmIouAlO/R+J4cNHMGWUW42xrYfTxhYnsY5Yfbijy4O685lR/c1iXeg8ArGFblblniQEjLs7Tbb4=</InverseQ>\r\n  <D>Km9lzmGvbjtLAzZ5Z6EQzyUKWrAgIbNGnm6u86kbHQ8h7/FZkCwNWRioHC+vUZsHE6696UBNbY68b8B6fC7nirhRexC4gBnaYaePhspPLeaIcnPYU4TegqIgGT7U/vTGmzNrqgUa4zbE6i3FzrZ/kJD3sQhzBoNwKp2ZS0reKRkrJyVZDVO0fRfHZLOS+d4uOb5XzngwFmmWcunlrPpCmG+mDUbQTR5Dd12x/qVI/LNgANJXdl4/A0ob9WA4D98agITkCyFbUXTHfZBLhTtCkNammAcCfPCV6HWFl52+I3VFP+SHfOZLS/Zwlc/fJ0BPVGi0izy+KvtRC3qsZtmPlQ==</D>\r\n</RSAParameters>");


    Console.WriteLine(Convert.ToBase64String(cryptoServiceProvider.Encrypt(Encoding.Default.GetBytes(value), true)));

}


private static void Main()

{

    try

    {

        Encrypt("Test");

    }

    catch (Exception e)

    {

        Console.WriteLine(e);

    }


    Console.ReadLine();

}


This will output the following cipher text for ?Test? in Base64 encoding on the console.


DctjVLlXN61aMU4NWLJwz46c/t3UlwJ67yTBsSBXwltf9Wvi2JY0HT6kj0Ls3wvQTiFPB426Qkg7A3LejpcIdRcPWb7jZiBUnbAZveIcRPyi/I0qppOeBfleEQYwTmIcFZAuJ0P9N/8fTOQEJNJjCSQBTaf+gbMAFnz04lnsEFnk2XnwJfAk73B0dmb/PKdbCY5ijXwigk+6ftWZsKgRFWMY4cDCeyKibJMhwoGtVLq/Rc2vrCE3YbOPbEWnKW+v+DuJlOGJvWzGNTLT4rCQhhyvSI2SvV3Kni9hJbhM3tI9rgcnY7f/F0jpoUAPCsGEcHgSZAhSXYPCviuoxUySIw==


As you can see both cipher texts do not match. Can you please give me a hint which property I am not using correctly to get the same results in Delphi and .NET.


I also noted that the public exponent in Delphi differs from the one passed to the property of the RSA object when logging it to the console. May be this could be the difference?


Thank you in advance!


Regards,

Maik

Hi Maik,
Thank you for your complete answer.
Firstly, our key are not encoded like in .NET. To convert .NET keys, you need to use the TConvert component and the KeyRSAOpenSSLToKeyTRSAEncSign method.
Secondly, you use OAEP padding method in Delphi code, are you sure RSACryptoServiceProvider uses this method? The PKCS#1 v1.5 is a more used method (although less secure).
Finally, OAEP and PKCS#1 v1.5 encryption method uses random padding, so it is normal that the cipher texts differ between .NET and Delphi.
I cannot test if all these changes are sufficient. But the Delphi code can be :

uses

  System.SysUtils, RSAObj, MiscObj;


procedure Encrypt(Value: string);

var

  RSA: TRSAEncSign;

  conv: TConvert;

begin

  RSA := TRSAEncSign.Create;

  conv := TConvert.Create(base64);


  RSA.keyLength := kl2048;

  RSA.encType := epkcs1_5;

  RSA.outputFormat := base64;


  RSA.modulus := Conv.KeyRSAOpenSSLToKeyTRSAEncSign('uzbtMdjXwkhvggQctl7TLg/YkM1UxHLqtj8zcntD/O/M+T/gCpMYRFjgHaM9+c1PwCFkG5yBw5VB0nxKUjoAnSo1K9PgGSHWUk4WRXtNrIRkUITQGQsU3GPLDHDzbu0w' +

                 '4+1v/UGE7POK5i3f64g70VdtwjQ3v7pa2soTWd/Mgah7WO33lJKC8RgM9HDo54874YFnFT+vgfP5wRYNHTb3UEITS/+qE4xooZtR0vzgWXymkb1f4MPFh5pm5S9dnAI5' +

                 'qRI2iqowYdpUitZAnnOPfR2lmQLeyH4D2wX6GycgnzFK5N6994jQl+Dn/qy8UbNUP647z5cl8KLfYtNZCg46ZQ==');


  RSA.PublicExponent := Conv.KeyRSAOpenSSLToKeyTRSAEncSign('AQAB');


  WriteLn(RSA.Encrypt(Value));

end;


begin

  try

    Encrypt('Test');

  except

    on E: Exception do

      Writeln(E.ClassName, ': ', E.Message);

  end;


  Readln;

end.

Tell me if the issue still remains.


Best regards,

Marion

Hi Marion,


I tested both encryption types with the conversion method for modulus and the public exponent as you suggested. Unfortunately decryption in .NET still fails.

Do you have any other ideas? What do you need to analyze the problem?

Regards,
Maik
Hi Maik,

Do you know which hash function is used in RSACryptoServiceProvider?
In our component, we use SHA-256.

Best regards,
Marion

Hi Marion,


Key exchange algorithm: RSA-PKCS1-KeyEx

Regards,
Maik
Our component does not support SHA-1 algorithm because many organizations have recommended its replacement by SHA-2 or SHA-3.

Best regards,
Marion

Hi Marion,


there is another RSA algorithm available in .NET (RSACng) which is using OAEP padding with SHA256 signature. Unfortunately this one also fails decrypting the ciphered string created with the TMS library in Delphi.

Any suggestions?

Regards,
Maik
Hi Maik,

I need some time to test my OAEP implementation and compare it with .NET RSACng algorithm.

Best regards,
Marion
Hi Maik,

Have you tried to put "false" instead of "true" here?
Console.WriteLine(Convert.ToBase64String(cryptoServiceProvider.Encrypt(Encoding.Default.GetBytes(value), true)));

"true" means for OAEP (and I think my implementation is not fully interoperable) and "false" means for PKCS#1 v1.5.

I am working to fix the bug on my OAEP implementation.

Best regards,
Marion

Hi Marion,


yes, of course. But it is not working when I encrypt in Delphi and try to decrypt in .NET.

Regards,
Maik

Hi Marion,


I did more tests also with another crypto library for .NET with the name "BouncyCastle Crypto". I think you have an issue with the public exponent in your implementation of RSA. I have generated the following key parameters and exported them in Base64 encoding.


Modulus: Tb4CdAMiMWpSzvuehXga4vL1hus2vf+rlJBwfOp8TRCnaPsQrjjJGruX1UFnF4pFijra6vRKR+dU02khPEGLXFNwwBoskhlXEY5kb3doC+iRvYQnasC/m0A53T/QAsh6oJKPK9pUdkNyhLXZH+qaN7qsSG+EisqQE13bO5NM/JR/2jXEzJTyhwjxYL7+p/UGeJ7pacq1eEFeazHz16nYGZM07o3Qw7ezX4CVjyCOMaR7TsSj1+OReWBSm2AMYeKrkWdV84TVhHoTEIASZqLRBbk6t8LlNHNX6IpOTklO9BpJeYrvRT01+wjoM33Bp9aPoTqfBbD7LFANILQKQ+EZgg==

Public exponent: BwAAAAAAIBAAQAAACAAAAAAEAAAAAAAAAAAAAAAAAAA=

Private exponent: s7BXdBqmHKK0HtpKBy1Rb6uLss7LZA+DxYa4z0L46PThG+FsCX6Xl8j/UyGXgnUGAwfzvKp5ioTnML4A+DMqKmXX/xqcNG5AiXLDGNwO3TCjD5rtwemg6faYCKmmiOIpuRJ+oEJ1mOltGtjRiX314YIDDP6P1m2kzlbbAkWJrMxHR4tlHrdFp9Cuw61m1clZ1KAaUCpqbVNfUOdPmsEPSU1Xn8QO3NyeWCTxcnBGHDKtmwuoknUjMeztWM0+IxBVJVmIXjpSluR11NW4m8P4HVjHDzdCdIm1/v7MYkpOfRviIuJsR8yfVEXqzuuzd437oTNkiPbWbXICElHyko1QbQ==


When I now try to construct an private key object for RSA with the BCCrypto library I receive an exception saying that the provided public exponent is even and the creation of the object fails.


As mentioned before I have also noticed that my public exponent generated in .NET (AQAB) is changed when providing it to your RSA library and logging it to the console in its Base64 representation (AQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=). It also makes no difference wether I use the Convert object or not.


Here is the code of my Delphi test application.


uses

  System.SysUtils, RSAObj, MiscObj;


var

  RSA: TRSAEncSign;


begin

  try

    RSA := TRSAEncSign.Create;


    RSA.keyLength := kl2048;

    RSA.encType := oaep;

    RSA.outputFormat := base64;


    RSA.modulus :=

      'nHOjA+WQ8NgRJ1O2ZvbQE7h3RaxBNGCxwwudVvGcqjE4+bmhO9hE/2iX/uZEhTNDEEVS6OSm3aO/jEpjJ3iu+baZq16Zd3leAgNmvISlREbu25OaMA1sN/an9Hkrda5es9xcnRoCvPfv76'

      + 'WXFSaaag+mIE9vlZG7InR9kOdESNHXvaFkhAOW7lPquVv/jwsCtP/jXSOvRWSXjvSFJvoiP1i1MKd4imFg/TUk8LRQ1onehiyMs1719AH5rOjPr/lasTB0Do8Zc3NwEkj2+W2ylMZYH5KvQ1YkF6bc6sg40nq4hWgyZ3a9MmacPP3u4m9nbyO8WCPpcYY3uXwDn6tl4Q==';


    RSA.PublicExponent := 'AQAB';


    WriteLn('Modulus: ' + RSA.modulus);

    WriteLn('Public Exponent: ' + RSA.PublicExponent);

  except

    on E: Exception do

      WriteLn(E.ClassName, ': ', E.Message);

  end;


  Readln;


end.


And this is the console output.


Modulus: nHOjA+WQ8NgRJ1O2ZvbQE7h3RaxBNGCxwwudVvGcqjE4+bmhO9hE/2iX/uZEhTNDEEVS6OSm3aO/jEpjJ3iu+baZq16Zd3leAgNmvISlREbu25OaMA1sN/an9Hkrda5es9xcnRoCvPfv76WXFSaaag+mIE9vlZG7InR9kOdESNHXvaFkhAOW7lPquVv/jwsCtP/jXSOvRWSXjvSFJvoiP1i1MKd4imFg/TUk8LRQ1onehiyMs1719AH5rOjPr/lasTB0Do8Zc3NwEkj2+W2ylMZYH5KvQ1YkF6bc6sg40nq4hWgyZ3a9MmacPP3u4m9nbyO8WCPpcYY3uXwDn6tl4Q==

Public Exponent: AQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=


I hope this helps for your further investigations.


Regards,

Maik

Hi Marion,


do you have any news regarding this issue?

Regards,
Maik
Hi Maik,

I fixed the bug for PKCS#1 v1.5 and I am working on the one in OAEP.

Best regards,
Marion
Hi Maik,

I fixed the bug in OAEP, I will release a new version soon.

Best regards,
Marion

Hi Marion,


do you have any information when the new release will be available so I can continue testing my implementation. I am asking due to a deadline for my project which needs RSA encryption in Delphi and RSA decryption in .NET by the end of the week. Thank you!

Regards,
Maik
Hi Maik,

I will send the new release to the internal review process today, but I cannot guarantee the release will be available before the end of the week, because it does not only depend on me.

Best regards,
Marion