使用PHP和C#进行Mcrypt和Base64编码解码

8
我已经在两个平台上写了相同的方法,我认为应该得到相同的结果,但实际上并没有。我已经用相同的密钥加密了相同的文本,但结果不同。有人能找出原因吗?
文本:this is test 密钥:1234567812345678 PHP加密字符串:ybUaKwQlRNwOjJhxLWtLYQ== C#加密字符串:r2YjEFPyDDacnPmDFcGTLA== C#函数:
static string Encrypt(string plainText, string key)
{
    string cipherText;
    var rijndael = new RijndaelManaged()
    {
        Key = Encoding.UTF8.GetBytes(key),
        Mode = CipherMode.ECB,
        BlockSize = 128,
    };
    ICryptoTransform encryptor = rijndael.CreateEncryptor(rijndael.Key, rijndael.IV);

    using (var memoryStream = new MemoryStream())
    {
        using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
        {
            using (var streamWriter = new StreamWriter(cryptoStream))
            {
                streamWriter.Write(plainText);
                streamWriter.Flush();
            }
            cipherText = Convert.ToBase64String(memoryStream.ToArray());
            //cryptoStream.FlushFinalBlock();
        }
    }
    return cipherText;
}

private static string Decrypt(string cipherText, string key)
{
    string plainText;
    byte[] cipherArray = Convert.FromBase64String(cipherText);
    var rijndael = new RijndaelManaged()
    {
        Key = Encoding.UTF8.GetBytes(key),
        Mode = CipherMode.ECB,
        BlockSize = 128
    };
    ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);

    using (var memoryStream = new MemoryStream(cipherArray))
    {
        using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
        {
            using (var streamReader = new StreamReader(cryptoStream))
            {
                plainText = streamReader.ReadToEnd();
            }
        }
    }
    return plainText;
}

PHP函数

function string_encrypt($string, $key) {
    $crypted_text = mcrypt_encrypt(
                            MCRYPT_RIJNDAEL_128, 
                            $key, 
                            $string, 
                            MCRYPT_MODE_ECB
                        );
    return base64_encode($crypted_text);
}

function string_decrypt($encrypted_string, $key) {
    return mcrypt_decrypt(
                    MCRYPT_RIJNDAEL_128, 
                    $key, 
                    base64_decode($encrypted_string), 
                    MCRYPT_MODE_ECB
                    );
}

我在C#方面不太擅长,但我知道PHP函数运作良好。因此,在C#函数上必须做些改进。也许应该将要加密的字符串转换为拉丁字符。


你得到的答案hsuk有什么问题吗?它似乎相当详尽... - Maarten Bodewes
实际上,我不想改变我的PHP函数... - hsuk
1
StigM 写的第二个代码块怎么样?那看起来像是 C#。他首先向您展示了正确的方法,然后展示了如何使 C# 与愚蠢的 PHP mcrypt_decrypt 功能兼容。 - Maarten Bodewes
请注意,您应明确定义在PHP和C#中使用的[标签:字符编码]。还要注意,密钥和密码不同,并且ECB模式不安全用于加密文本(或大多数数据)。 - Maarten Bodewes
1个回答

8

C#默认使用Rijndael填充并使用PKCS7。

这意味着您必须按照PKCS7填充您的PHP端,下面的代码应该可以工作:

function string_encrypt($string, $key) {

  $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
  $padding = $block - (strlen($string) % $block);
  $string .= str_repeat(chr($padding), $padding);

    $crypted_text = mcrypt_encrypt(
                            MCRYPT_RIJNDAEL_128, 
                            $key, 
                            $string, 
                            MCRYPT_MODE_ECB
                        );
    return base64_encode($crypted_text);
}

如需更多信息,请参见此处的第一个答案

我还应该补充一点,如果您想更改C#端而不使用填充,请进行以下修改而不是更改PHP端:

static string Encrypt(string plainText, string key)
{
  string cipherText;
  var rijndael = new RijndaelManaged()
  {
    Key = Encoding.UTF8.GetBytes(key),
    Mode = CipherMode.ECB,
    BlockSize = 128,
    Padding = PaddingMode.Zeros,
  };
  ICryptoTransform encryptor = rijndael.CreateEncryptor(rijndael.Key, null);

  using (var memoryStream = new MemoryStream())
  {
    using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
    {
      using (var streamWriter = new StreamWriter(cryptoStream))
      {
        streamWriter.Write(plainText);
        streamWriter.Flush();
      }
      //cipherText = Convert.ToBase64String(Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(memoryStream.ToArray())));
      cipherText = Convert.ToBase64String(memoryStream.ToArray());
      //cryptoStream.FlushFinalBlock();
    }
  }
  return cipherText;
}

如果在这个答案中,PaddingMode.Zeros更加突出就太棒了。谢谢! - Nick Westgate

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接