TripleDES 加密在 c# 和 PHP 中没有得到相同的结果

Posted

技术标签:

【中文标题】TripleDES 加密在 c# 和 PHP 中没有得到相同的结果【英文标题】:TripleDES encription not getting same results in c# and PHP 【发布时间】:2014-07-07 09:21:23 【问题描述】:

C# 返回以下 base64 编码字符串:

joxzS5XnP63ymrhy6t4ogWK9TxwfwD83

下面是c#代码

我们

ing System.IO;
using System;
using System.Text;
using System.Security.Cryptography;

class Program

    static void Main()
    
        // Read in every line in the file.
        using (StreamReader reader = new StreamReader("input.txt"))
        
            string abc = "string to encrypt";
            Program p = new Program();
            string value =    p.Encrypt(abc, true);
            Console.Write(value);
        
    

    public string Encrypt(string toEncrypt, bool useHashing)
        
            byte[] keyArray;
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

            //System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
            // Get the key from config file
            string key = "encrypt key";
            //System.Windows.Forms.MessageBox.Show(key);
            if (useHashing)
            
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                hashmd5.Clear();
            
            else
                keyArray = UTF8Encoding.UTF8.GetBytes(key);

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            tdes.Key = keyArray;
            tdes.Mode = CipherMode.ECB;
            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateEncryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
            tdes.Clear();
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        



我在 php 中使用 MCrypt 库,它返回

ThPKJ1BPJLeUwJtIT/zAs3ocZ2s6SU+M

PHP 代码:

$str = "string to encrypt";

$input = utf8_encode($str);
$key = "encrypt key";
echo apiEncode($input, $key);


function apiEncode($data, $secret)
    
  //Generate a key from a hash
  $key = md5(utf8_encode($secret), true);
  //Create init vector  
  $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_3DES, MCRYPT_MODE_ecb), MCRYPT_RAND); 

  //Pad for PKCS7
  $blockSize = mcrypt_get_block_size('tripledes', 'ecb');
  $len = strlen($data);
  $pad = $blockSize - ($len % $blockSize);
  $data .= str_repeat(chr($pad), $pad);

  //Encrypt data
  $encData = mcrypt_encrypt('tripledes', $key, $data, 'ecb'); //, $iv);
  return base64_encode($encData);

除了上述之外,我还尝试了在 so 找到的各种其他解决方案

tripledes encryption not yielding same results in PHP and C#

TripleDES Encrypting in C# and PHP not coming out the same (PKCS7, ECB)?

【问题讨论】:

【参考方案1】:

您的 C# 代码没有设置 IV,因此您的 IV 将是一个零块。我不懂 PHP,但我强烈怀疑 mcrypt_create_iv() 创建了一个重要的 IV。

除此之外,您应该考虑 CBC 模式而不是 ECB 模式。

【讨论】:

如果我从 php 代码中删除 IV 语句,它不会影响。 您提供的第二个链接指出 mcrypt_encrypt() 实际上并不使用 128 位密钥;但它不会返回错误,而是用零填充键。您使用 md5() 派生的密钥正是 128 位密钥。我不确定我是否喜欢使用散列函数派生密钥,但如果您坚持这样做,请改为从 SHA-256 散列中提取 192 位或 256 位。 根据php.net/manual/en/function.mcrypt-encrypt.php,您必须在 mcrypt_encrypt() 中为 3DES 使用 192 位密钥。 256 位是我将 3 键 3DES 与 AES 混合。对不起。【参考方案2】:

Considering the Security vulnerabilities of DES and TripleDES,两边都实现了 AES/RIJNDAEL_256 算法。

C#

    public String DecryptRJ256(string cypher, string KeyString, string IVString)
    
        string sRet = string.Empty;
        RijndaelManaged rj = new RijndaelManaged();
        UTF8Encoding encoding = new UTF8Encoding();

        byte[] decbuff = Convert.FromBase64String(cypher);

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

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

            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;
    

public string Encrypt(string message, string KeyString, string IVString)
    
        byte[] Key = ASCIIEncoding.UTF8.GetBytes(KeyString);
        byte[] IV = ASCIIEncoding.UTF8.GetBytes(IVString);

        string encrypted = null;
        RijndaelManaged rj = new RijndaelManaged();
        rj.BlockSize = 256;
        rj.Key = Key;
        rj.IV = IV;
        rj.Mode = CipherMode.CBC;

        try
        
            MemoryStream ms = new MemoryStream();

            using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
            
                using (StreamWriter sw = new StreamWriter(cs))
                
                    sw.Write(message);
                    sw.Close();
                
                cs.Close();
            
            byte[] encoded = ms.ToArray();
            encrypted = Convert.ToBase64String(encoded);

            ms.Close();
        
        catch (CryptographicException e)
        
            Console.WriteLine("A Cryptographic error occurred: 0", e.Message);
            return null;
        
        catch (UnauthorizedAccessException e)
        
            Console.WriteLine("A file error occurred: 0", e.Message);
            return null;
        
        catch (Exception e)
        
            Console.WriteLine("An error occurred: 0", e.Message);
        
        finally
        
            rj.Clear();
        

        return encrypted;
    

PHP

public function apiEncode($text, $key, $iv)

    // 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);
    return base64_encode($crypttext);


publc function apiDecode($text, $key, $iv)

    $text = base64_decode($text);
    $crypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
    return $crypttext;

【讨论】:

以上是关于TripleDES 加密在 c# 和 PHP 中没有得到相同的结果的主要内容,如果未能解决你的问题,请参考以下文章

C# 对 TripleDES 算法的实现

多语言(Java&C#&Ruby&C++&Objective-C&Android)互通的TripleDES加解密算法实现

加密算法:AES DES RC4 Rabbit TripleDes 那个更好??它们分

TripleDes的加密工作在Java罚款,但不是在C#

php和java中的加密和解密

java TripleDES加密