2010-12-01 57 views
18

我目前对解密php mcrypt加密的消息有点问题。 PHP代码是如下:Rijndael加密/解密的跨平台(php to 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

你不需要`urlencode`之前,你`base64_encode`它加密的数据。 – Powerlord 2010-12-01 21:41:55

回答

31

在这里,我可以看到双方的问题。

请记住,编码时得到的不是字符串,而是一个字节数组。 所以在PHP中,你不需要urlencode密码。

base64编码就是您所需要的。当您打开base64_encode help你看

BASE64_ENCODE使用Base64编码上述给出的数据。这种编码是 设计,使二进制数据生存运输

一两件事 - 有你的消息在.NET中有正确的长度解码,你有填充字符来手动添加它。 RijndaelManaged的默认填充模式是PKCS7,让我们坚持下去。您必须将源字符串扩展到字符代码等于填充字节数的偶数块。

<?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/>"; 
?> 

在C#侧您从的base64的byte []的byte []铸造。您必须完成从base64byte []的第一次转换。请记住,base64持有的是二进制数据的加密文本,而不是字符串。 另请注意,RijndaelManaged是IDisposable,所以我用()构造包装它。调用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 2012-01-01 09:32:37