3

(序文:私は暗号化とセキュリティの初心者ですが、これは楽しい学習方法だと思いました)

標準の HTTP プロトコルを使用して PHP で記述されたサーバーと通信するプログラムを C# で作成しています。両方のプログラムが暗号化されたデータを送受信できるようにします。ただし、どちらも同じ種類の機能を使用しているにもかかわらず、暗号化の処理方法に矛盾があるようです。

どちらのプログラムも、CBC モードで Rjindael 128 ビットを使用します。

デモンストレーション/テストのために、実質的に同一の 2 つの関数を作成しました。それぞれが同じ文字列を取得し、暗号化し、結果を base64 文字列として出力します。

PHP 関数:

public static function EncryptionTest () {
  echo 'Testing Encryption to base64 string...<br/>';

  $originalString = 'This is the original String! How cool is that?';

  $key = "abcdefghijklmnopqrstuvwxyz012345";
  $iv = "1234567890123456";

  $encrypted = mcrypt_encrypt (MCRYPT_RIJNDAEL_128, $key, $originalString, MCRYPT_MODE_CBC, $iv);

  echo base64_encode ($encrypted);
}

そして、それはC#の対応物です:

public static void EncryptionTest ()
{
  System.Console.WriteLine ("Testing Encryption to base64 string...");

  string originalString = "This is the original String! How cool is that?";
  byte [] encryptedData;
  byte [] key = System.Text.ASCIIEncoding.UTF8.GetBytes ("abcdefghijklmnopqrstuvwxyz012345");
  byte [] iv = System.Text.ASCIIEncoding.UTF8.GetBytes ("1234567890123456");

  RijndaelManaged cryptor = new RijndaelManaged ();
  cryptor.Key = key;
  cryptor.IV = iv;
  cryptor.BlockSize = 128;
  cryptor.Mode = CipherMode.CBC;

  ICryptoTransform encryptor = cryptor.CreateEncryptor (cryptor.Key, cryptor.IV);

  using (MemoryStream msEncrypt = new MemoryStream ())
  {
    using (CryptoStream csEncrypt = new CryptoStream (msEncrypt, encryptor, CryptoStreamMode.Write))
    {
      using (StreamWriter swEncrypt = new StreamWriter (csEncrypt) )
      {
        swEncrypt.Write (originalString);
      }
      encryptedData = msEncrypt.ToArray ();
    }
  }

  System.Console.WriteLine (System.Convert.ToBase64String (encryptedData) );
}

さて、PHPの結果は次のとおりです。

base64 文字列への暗号化をテストしています...

そしてC#の結果:

base64 文字列への暗号化をテストしています...

ご覧のとおり、2 つの結果は明らかに暗号化されており (良好)、同じ文字数 (良好) ですが、異なっています (不良の可能性があります)。

これらの文字列を取得して処理する復号化テストを作成しました。PHP関数は次のとおりです。

public static function DecryptionTest () {
  $phpBase64 = 'yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUOJdFykLjsaKfK4VfaBGRv';
  $csBase64 =  'yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUg74mGEQf9iW+OQ68m6cpp';

  $key = "abcdefghijklmnopqrstuvwxyz012345";
  $iv = "1234567890123456";

  $phpEncrypted = base64_decode ($phpBase64);
  $phpDecrypted = mcrypt_decrypt (MCRYPT_RIJNDAEL_128, $key, $phpEncrypted, MCRYPT_MODE_CBC, $iv);

  $csEncrypted = base64_decode ($csBase64);
  $csDecrypted = mcrypt_decrypt (MCRYPT_RIJNDAEL_128, $key, $csEncrypted, MCRYPT_MODE_CBC, $iv);

  echo 'Decrypted PHP string: "' . $phpDecrypted . '"<br/>' .
       'Decrypted CS string:  "' . $csDecrypted . '"';
}

そしてC#バージョン:

public static void DecryptionTest ()
{
  System.Console.WriteLine ("Testing Decryption for PHP and CS generated base64 strings!");

  string phpBase64 = "yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUOJdFykLjsaKfK4VfaBGRv";
  string csBase64 = "yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUg74mGEQf9iW+OQ68m6cpp";

  byte [] phpEncrypted = System.Convert.FromBase64String (phpBase64);
  byte [] csEncrypted = System.Convert.FromBase64String (csBase64);

  string phpDecrypted;
  string csDecrypted;

  byte [] encryptedData;
  byte [] key = System.Text.ASCIIEncoding.UTF8.GetBytes ("abcdefghijklmnopqrstuvwxyz012345");
  byte [] iv = System.Text.ASCIIEncoding.UTF8.GetBytes ("1234567890123456");

  RijndaelManaged cryptor = new RijndaelManaged ();
  cryptor.Key = key;
  cryptor.IV = iv;
  cryptor.BlockSize = 128;
  cryptor.Mode = CipherMode.CBC;

  ICryptoTransform decryptor = cryptor.CreateDecryptor (cryptor.Key, cryptor.IV);

  using (MemoryStream msDecrypt = new MemoryStream (csEncrypted))
  {
    using (CryptoStream csDecrypt = new CryptoStream (msDecrypt, decryptor, CryptoStreamMode.Read))
    {
      using (StreamReader swDecrypt = new StreamReader (csDecrypt) )
      {
        csDecrypted = swDecrypt.ReadToEnd ();
      }
    }
  }
  System.Console.WriteLine ("Decrypted CS string: \"" + csDecrypted + "\"");

  using (MemoryStream msDecrypt = new MemoryStream (phpEncrypted))
  {
    using (CryptoStream csDecrypt = new CryptoStream (msDecrypt, decryptor, CryptoStreamMode.Read))
    {
      using (StreamReader swDecrypt = new StreamReader (csDecrypt) )
      {
        phpDecrypted = swDecrypt.ReadToEnd ();
      }
    }
  }

  System.Console.WriteLine ("Decrypted PHP string: \"" + phpDecrypted + "\"");      
}

PHP の結果:

復号化された PHP 文字列: 「これは元の文字列です! なんてクールなの?」

復号化された CS 文字列: 「これが元の文字列です! なんてクールなの?」

C# の結果は次のとおりです。

復号化された CS 文字列: 「これが元の文字列です! なんてクールなの?」

CryptographicException: PKCS7 パディングが正しくありません。> /Applications/buildAgent/work/84669f285f6a667f/mcs/class/corlib/Mono.Security.Cryptography/ の Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException (PaddingMode padding、Int32 length、Int32 position) [0x0005c] で無効な長さ 0。 SymmetricTransform.cs:363

したがって、基本的に、PHP コードは両方の base64 文字列を正常に復号化できますが、C# コードは独自の復号化プログラムによって作成された base64 文字列のみを復号化できます。

これの多くは、インターネットで見つけたコードを自分のニーズに合わせて変更したものです。私が言ったように、私は暗号化の初心者ですが、ここまではかなり進んでいます。一日中理論を立ててテストすることもできましたが、スケジュールに食い込み始めているので、なぜうまくいかないのかについて他の人からの洞察を探しています. ありがとうございました!

4

1 に答える 1

4

実装は と互換性がないため、 PHPSecLibを使用する必要があります。パディングサイズが異なります(ここでは暗号の専門家ではありませんが、これは数日間のテストの後に見つけたものです)。したがって、でネイティブ実装を使用すると、機能します。PHPC++/C#phpseclib

少し前にこの問題にぶつかりました。しかし、C++/CryptoAPIPHP.

于 2013-06-28T18:59:49.530 に答える