2010-12-01 15 views
18

現在、php mcryptで暗号化されたメッセージの復号化に問題があります。 PHPコードは、次の通りである:Rijndaelによるクロスプラットフォーム(phpからC#.NET)の暗号化/復号化

<?php 
    //$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); 
    $iv = "45287112549354892144548565456541"; 
    $key = "anjueolkdiwpoida"; 
    $text = "This is my encrypted message"; 
    $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv); 
    $crypttext = urlencode($crypttext); 
    $crypttext64=base64_encode($crypttext); 
    print($crypttext64) . "\n<br/>"; 
?> 

暗号化されたメッセージは、その後、ASP.NETプラットフォーム(C#)とに送られます。しかし、私は解読の順序を保持する問題を抱えています(base64デコードからurldecodeへ)。私はASP.NETで持っていたコードは以下の通りです(IVおよびキーは、PHPの場合と同じである):

public string Decode(string str) 
{ 
    byte[] decbuff = Convert.FromBase64String(str); 
    return System.Text.Encoding.UTF8.GetString(decbuff); 
} 

static public String DecryptRJ256(string cypher, string KeyString, string IVString) 
{ 

    string sRet = ""; 
    RijndaelManaged rj = new RijndaelManaged(); 
    UTF8Encoding encoding = new UTF8Encoding(); 


    try 
    { 
     //byte[] message = Convert.FromBase64String(cypher); 
     byte[] message = encoding.GetBytes(cypher); 

     byte[] Key = encoding.GetBytes(KeyString); 
     byte[] IV = encoding.GetBytes(IVString); 

     rj.Padding = PaddingMode.Zeros; 
     rj.Mode = CipherMode.CBC; 
     rj.KeySize = 256; 
     rj.BlockSize = 256; 
     rj.Key = Key; 
     rj.IV = IV; 
     MemoryStream ms = new MemoryStream(message); 

     using (CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(Key, IV), CryptoStreamMode.Read)) 
     { 
      using (StreamReader sr = new StreamReader(cs)) 
      { 
       sRet = sr.ReadToEnd(); 
      } 
     } 

    } 
    finally 
    { 
     rj.Clear(); 
    } 

    return sRet; 


} 

string temp = DecryptRJ256(Server.UrlDecode(Decode(cypher)), keyString, ivString); 

私がいる問題は、私はPHPから暗号化されたメッセージを受け取った後、私は変換していることですそれをbyte []に​​変換してUTF8でエンコードされた文字列に変換して、私はそれをurldecodeできます。私はその結果を関数に渡します。ここで文字列をbyte []に​​変換し、解読プロセスを実行します。しかし、私は希望の結果を得ることができません...任意のアイデア?

ありがとうございます。

+0

をする 'それあなた' base64_encode'前に暗号化されたデータurlencode'。 – Powerlord

答えて

31

ここで私は両側の問題を見ることができます。

エンコードが文字列ではなく、バイト配列である場合に得られることに注意してください。 PHPでは、ciphertextをurlencodeする必要はありません。

base64エンコーディングがすべて必要です。あなたがbase64_encode helpを開くと、あなたは

参照BASE64_ENCODEは、base64で与えられたデータをエンコードします。このエンコードは、バイナリデータは、トランスポート

もう一つ生き残るにするために設計された です - あなたのメッセージが正しい長さで、.NETでデコード持っているが、手動でパディング文字でそれを追加する必要があります。 RijndaelManagedのデフォルトのパディングモードはPKCS7です。パッディングバイト数に等しい文字コードのブロックにソース文字列を拡張する必要があります。あなたはバイト[]に文字列にバイト[]base64でからキャストしているのC#側で

<?php 
    $iv = "45287112549354892144548565456541"; 
    $key = "anjueolkdiwpoida"; 
    $text = "This is my encrypted message"; 

    // to append string with trailing characters as for PKCS7 padding scheme 
    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); 
    $padding = $block - (strlen($text) % $block); 
    $text .= str_repeat(chr($padding), $padding); 

    $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv); 

    // this is not needed here    
    //$crypttext = urlencode($crypttext); 

    $crypttext64=base64_encode($crypttext); 
    print($crypttext64) . "\n<br/>"; 
?> 

ベース64からバイト[]からの最初の変換を行う必要があります。 Base64は文字列ではなく、バイナリデータである暗号化されたテキストを保持していることに注意してください。 また、RijndaelManagedはIDisposableなので、私はusing()を使ってラップしました。 Close()を呼び出す必要はありますが、MSDNに記載されているように十分ではありません。その結果、

public byte[] Decode(string str) 
{ 
    var decbuff = Convert.FromBase64String(str); 
    return decbuff; 
} 

static public String DecryptRJ256(byte[] cypher, string KeyString, string IVString) 
{ 
    var sRet = ""; 

    var encoding = new UTF8Encoding(); 
    var Key = encoding.GetBytes(KeyString); 
    var IV = encoding.GetBytes(IVString); 

    using (var rj = new RijndaelManaged()) 
    { 
     try 
     { 
      rj.Padding = PaddingMode.PKCS7; 
      rj.Mode = CipherMode.CBC; 
      rj.KeySize = 256; 
      rj.BlockSize = 256; 
      rj.Key = Key; 
      rj.IV = IV; 
      var ms = new MemoryStream(cypher); 

      using (var cs = new CryptoStream(ms, rj.CreateDecryptor(Key, IV), CryptoStreamMode.Read)) 
      { 
       using (var sr = new StreamReader(cs)) 
       { 
        sRet = sr.ReadLine(); 
       } 
      } 
     } 
     finally 
     { 
      rj.Clear(); 
     } 
    } 

    return sRet; 
} 

は、C#で、次のコードは、あなたの最初の文字列が返されます:あなたは必要ありません

var iv = "45287112549354892144548565456541"; 
var key = "anjueolkdiwpoida"; 
var cypher = "u+rIlHB/2rrT/u/qFInnlEkg2unhizsNzGVb9O54sP8="; 

var temp = DecryptRJ256(Decode(cypher), key, iv); 
+0

私はこれを試して、それは動作します!あなたがそれを投稿するのは素晴らしい。 – Yuki

+0

例のためによくできました。私は解読側でコードを完成させ、すべてを[要点](https://gist.github.com/2036829)に入れました –

+0

POSTから$ keyを受け入れるためにこのコードを試しました.c#アプリケーションが暗号化された文字列を解読します。このアルゴリズムに対して有効でない例外指定のキーがスローされます。私を助けてくださいhttp://stackoverflow.com/questions/10160690/php-encryption-and-decryption-with-data-from-post-method-using-c-sharp – techno