跨平台(php到C# .NET)加密/解密与Rijndael

2022-08-30 22:05:44

我目前在解密由php mcrypt加密的消息时遇到了一些问题。php 代码如下:

<?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和key与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[],并通过解密过程运行它。但是,我无法获得所需的结果...任何想法?

提前致谢。


答案 1

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

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

base64 编码就是您所需要的。当您打开base64_encode帮助您看到

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# 端,你可以从 base64byte[]stringbyte[] 的强制转换。您只需要执行从 base64byte[] 的第一次转换。请记住,base64 保存的是二进制数据(而不是字符串)的密码文本。另请注意,RijndaelManaged 是 IDisposable,因此我将其包装在 using() 构造中。调用 Close() 是必要的,但正如 MSDN 中所述,调用 Close() 是不够的。

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);

答案 2

推荐