Mcrypt 和 base64 与 PHP 和 c#

Posted

技术标签:

【中文标题】Mcrypt 和 base64 与 PHP 和 c#【英文标题】:Mcrypt and base64 with PHP and c# 【发布时间】:2013-09-25 08:38:54 【问题描述】:

我在两个平台上编写了相同的方法,我认为这些方法应该会产生相同的结果,但它没有发生。我用相同的密钥加密了相同的文本,结果不同。有人能弄清楚为什么会这样吗?

字符串:这是测试

密钥: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 给你的答案有什么问题吗?它似乎相当广泛...... 其实我并不想改变我的PHP函数... StigM 编写的第二个代码块呢?对我来说,这看起来像 C#。他先给大家展示了正确的方法,然后是让C#符合脑残的PHP mcrypt_decrypt功能的方法。 另外请注意,您应该明确定义要在 PHP 和 C# 中使用的 character-encoding。另请注意,密钥和密码不一样,ECB 模式对于加密文本(或实际上对于大多数数据)并不安全。 【参考方案1】:

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

有关详细信息,请参阅first answer here

我还应该补充一点,如果您想更改 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 在这个答案中更突出,那就太好了。谢谢!

以上是关于Mcrypt 和 base64 与 PHP 和 c#的主要内容,如果未能解决你的问题,请参考以下文章

对称加密和Base64编码

与 java 和 .net 相比,mcrypt blowfish php 结果略有不同

php使用内置的mcrypt_encrypt和mcrypt_decrypt进行字符串加密解密

使用 nodejs crypto 与 php 的 mcrypt 解密 Blowfish-ecb

PHP7.1 mcrypt 替代方案

80分求DES加密解密算法实现的PHP源代码