Я пытаюсь расшифровать строку на С#, которая была зашифрована в PHP с помощью RSA, и, хоть убей меня, я не могу сделать это правильно. Я свел проблему к двум примерам тестовых приложений в .NET и PHP:

В 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();
    }
  }

В первый раз, когда я запускаю это, он выводит (хорошо отформатированный):

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

Я проверил, что ключ сохраняется и правильно загружается между запусками.

Затем я делаю это в PHP, используя 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)

Это выводит мою расшифрованную строку:

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

Наконец, когда я снова запускаю свое приложение C# с этим в качестве входных данных, я получаю следующее исключение при вызове метода Decrypt:

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:

Честно говоря, я нахожусь в такой ситуации, когда не знаю, что еще я могу попробовать. Любые предложения о том, что может пойти не так, или что еще я мог бы попробовать, будут очень кстати.

2
michael_erasmus 29 Мар 2011 в 18:33
Crypt_RSA — это просто игрушка. Он не использует стандартные схемы заполнения, поэтому он не будет взаимодействовать с .NET (или Java, или OpenSSL, или чем-то серьезным).
 – 
President James K. Polk
30 Мар 2011 в 04:08
Так что еще я могу использовать, OpenSSL? Я просмотрел его, и кажется, что openssl_public_encrypt - это то, что я ищу, но я не вижу, как создать открытый ключ из .NET xml...
 – 
michael_erasmus
30 Мар 2011 в 10:47
Я не знаю, что использовать, но openssl должен работать. Вы можете использовать возможности декодирования base64 в openssl, чтобы помочь вам декодировать XML.
 – 
President James K. Polk
30 Мар 2011 в 15:37

1 ответ

Известная проблема. Восстановить порядок байтов в блоке.

1
Seva Alekseyev 29 Мар 2011 в 18:35
Я уже пробовал это и получил то же самое (неверные данные): var encrypted = Convert.FromBase64String(args[0]); Array.Reverse(encrypted); string decrypted = Encoding.UTF8.GetString(provider.Decrypt(encrypted, false));
 – 
michael_erasmus
29 Мар 2011 в 18:41
IIRC, Crypt/RSA не реализует правильное заполнение блоков. Попробуйте функции OpenSSL. У меня нет готового примера шифрования, извините - только подпись/проверка.
 – 
Seva Alekseyev
29 Мар 2011 в 18:45
Я использовал API Win32 против .NET. Обращение байтов в .NET позволило читать байты, зашифрованные с помощью Win32 API.
 – 
earlNameless
6 Сен 2012 в 07:09