2

I am trying to decrypt a string in C# that was encrypted in PHP using RSA, and for the life of me, I can't get it right. I have condensed the problem to two sample test apps in .NET and PHP:

In C#:

class Program
  {
    static void Main(string[] args)
    {

      RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
      string fileName = @"C:\privateKey";
      if (File.Exists(fileName))
      {
        provider.FromXmlString(File.ReadAllText(fileName));  
      }
      else
      {
      File.WriteAllText(fileName, provider.ToXmlString(true));
      }
      if(args.Length > 0)
      {
       string decrypted = Encoding.UTF8.GetString(provider.Decrypt(Convert.FromBase64String(args[0]), false));
        Console.WriteLine("decrypted: {0}", decrypted);
      }
      else
      {
        Console.WriteLine(provider.ToXmlString(false));
      }
      Console.ReadLine();
    }
  }

The first time I run this, it outputs(nicely formatted):

<RSAKeyValue>
  <Modulus>
    2P8G+ospDboN87+FIWSzFA9E1QVXCDy4bO9YZPe1MTcxO7VhlBYmLy1J7b
    rSheaTa8RamrdeXe2Ev0y5O7zyxo/Bxw4W2UfnVAAFK+bgb8f0FicnSosAlGC95m5Goid9wWPf/QtqDa
    NxSMBBjULA1WKzA7+3HQncAenODYypOiE=
  </Modulus>
  <Exponent>AQAB</Exponent>
</RSAKeyValue>

I have verified that the key gets saved and loaded correctly between runs.

Then I do this in PHP using the Crypt_RSA Package:

include('Crypt/RSA.php');
$keyXML = <<<EOS
<RSAKeyValue>
  <Modulus>2P8G+ospDboN87+FIWSzFA9E1QVXCDy4bO9YZPe1MTcxO7VhlBYmLy1J7brSheaTa8RamrdeXe2Ev0y5O7zyxo/Bxw4W2UfnVAAFK+bgb8f0FicnSosAlGC95m5Goid9wWPf/QtqDaNxSMBBjULA1WKzA7+3HQncAenODYypOiE=</Modulus>
  <Exponent>AQAB</Exponent>
</RSAKeyValue>
EOS;
$doc = DOMDocument::loadXML($keyXML);
$modulus = $doc->getElementsByTagName("Modulus")->item(0)->nodeValue;
$exponent = $doc->getElementsByTagName("Exponent")->item(0)->nodeValue;
$key = Crypt_RSA_Key::factory(base64_decode($modulus), base64_decode($exponent), 'public'); 

$crypt = new Crypt_RSA();

echo $crypt->encrypt("hello", $key)

This outputs my decrypted string:

CBGFdK+NXq39ZigXkW6JChHHCCUTzHzjsEPqdoaNJtZgTCRQfIIR6IU4m5LOHGidLaLWN7cIM9ImNdSsAsMH9awkZ7uW0KXdqQjhVGeXzmC6EuSHqrSzYiIZp+1F5Rxhg/JFD/Or3eQ+UIHm/4YtNTyys6S3maClitk5KV68lhs=

Finally, when I run my C# app again with this as input, I get the following exception when I call the Decrypt method:

System.Security.Cryptography.CryptographicException was unhandled
  Message=Bad Data.
  Source=mscorlib
  StackTrace:
       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 ConsoleApplication1.Program.Main(String[] args) in C:\development\FundCentric\src\Utilities\ConsoleApplication1\ConsoleApplication1\Program.cs:line 27
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

Frankly, I'm at a point where I don't know what else I can try anymore. Any suggestions at what could be possibly going wrong or what else I could try would be very welcome.

earlNameless
  • 2,878
  • 20
  • 25
michael_erasmus
  • 906
  • 1
  • 9
  • 17
  • Crypt_RSA is just a toy. It doesn't use standard padding schemes so it won't interoperate with .NET (or Java, or OpenSSL, or anything serious). – President James K. Polk Mar 30 '11 at 00:08
  • So what else can I use, OpenSSL? I had a look at it, and it seems like `openssl_public_encrypt` is what I'm looking for but I can't see how to create a public key from the .NET xml... – michael_erasmus Mar 30 '11 at 06:47
  • I don't know what to use but openssl should work. You can use the base64 decoding capabilities of openssl to help you decode the XML. – President James K. Polk Mar 30 '11 at 11:37

1 Answers1

1

Known issue. Revert the byte order in the block.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • I already tried that and got the same thing(bad data): `var encrypted = Convert.FromBase64String(args[0]);` `Array.Reverse(encrypted);` `string decrypted = Encoding.UTF8.GetString(provider.Decrypt(encrypted, false));` – michael_erasmus Mar 29 '11 at 14:41
  • IIRC, Crypt/RSA does not implement proper block padding. Try OpenSSL functions. I don't have a ready encryption example, sorry - just signing/verification. – Seva Alekseyev Mar 29 '11 at 14:45
  • I was using Win32 APIs vs .NET. Reversing the bytes in .NET allowed it to read bytes encrypted by Win32 APIs. – earlNameless Sep 06 '12 at 03:09