【问题标题】:TripleDES Encrypting in C# and PHP not coming out the same (PKCS7, ECB)?C# 和 PHP 中的 TripleDES 加密不一样(PKCS7、ECB)?
【发布时间】:2011-06-09 09:16:59
【问题描述】:

我现在已经花了几个小时试图解决这个问题,但我就是无法让它发挥作用。我有一个需要在 php 中匹配的 C# 加密例程。我无法更改 C# 版本,这不是一个选项(第三方对此很坚定)。

这是 C# 代码:

//In C#
// Console.WriteLine(ApiEncode("testing", "56dsfkj3kj23asdf83kseegflkj43458afdl"));
// Results in: 
//     XvHbR/CsLTo=
public static string ApiEncode(string data, string secret)
{
  byte[] clear;

  var encoding = new UTF8Encoding();
  var md5 = new MD5CryptoServiceProvider();

  byte[] key = md5.ComputeHash(encoding.GetBytes(secret));

  TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
  des.Key = key;
  des.Mode = CipherMode.ECB;
  des.Padding = PaddingMode.PKCS7;

  byte[] input = encoding.GetBytes(data);
  try { clear = des.CreateEncryptor().TransformFinalBlock(input, 0, input.Length); }
  finally
  {
    des.Clear();
    md5.Clear();
  }

  return Convert.ToBase64String(clear);
}

这是我在 PHP 中提出的最好的:

//In PHP
// echo apiEncode("testing", "56dsfkj3kj23asdf83kseegflkj43458afdl");
// Results in: 
//    5aqvY6q1T54=
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);
}

据我所知,我正在 PHP 端正确处理 PKCS7 填充。我不确定还能尝试什么。

需要注意的是,C# 是在 windows 上发生的,而 PHP 是在 linux 上发生的,不确定是否会有所作为。

【问题讨论】:

  • 可能是字符编码不同 - 它在 c# 中显式 utf-8,但它在 php 中是什么?两种语言的 md5 调用的输出是什么。
  • @netcoder - 答案不太一样,所以我想说不是重复的。
  • 我看到了另一个问题,我尝试使用它,但我仍然无法正常工作,这就是我发布另一个问题的原因..
  • 如果我这样做:$strArr = str_split($key); foreach ($strArr as $strChar) echo(" " .ord($strChar));我得到: 77 173 222 29 122 78 74 3 80 240 63 130 5 137 93 188 在计算 md5 哈希后,这与我的 c# byte[] 键中的字节相同。键是一样的。

标签: c# php encryption cryptography tripledes


【解决方案1】:

您的 PHP 版本中的填充长度基于密码的长度。这是不正确的。它应该基于您的消息的长度。

尝试将strlen($password) 替换为strlen($data)


第二个问题是mcrypt 库需要 24 字节的密钥。 Triple DES 应用常规 DES 三次,因此可以调用每轮 DES 中使用的 8 字节密钥 K1、K2 和 K3。有不同的方法来选择这些键。最安全的是选择三个不同的密钥。另一种方法是设置 K3 等于 K1。最不安全的方法(相当于DES)是让K1 = K2 = K3

大多数库都足够“智能”,可以将 16 字节 3DES 密钥解释为上述第二个选项:K3 = K1。 .NET 实现为您执行此操作,但 mcrypt 库不是;相反,它设置了 K3 = 0。你需要自己解决这个问题,并传递 mcrypt 一个 24 字节的密钥。

计算完 MD5 哈希后,取$key 的前 8 个字节,并将它们附加到$key 的末尾,这样你就有一个 24 字节的值可以传递给mcrypt_encrypt()

【讨论】:

  • 修复了上面的示例代码,我正在测试我的代码。我仍然没有从两者中得到相同的加密字符串,所以显然不是......
  • @Redth - 你现在得到了什么结果?当您应该只有一个(12 个字符)时,您仍然得到 2 个密文块(24 个字符)吗?
  • @erickson 不,你说得对,我现在确实得到了一个密文块:5aqvY6q1T54= 是我现在来自 PHP 的 base64_encode($encData) 结果
  • @Redth - 嗯。由于您使用的是 ECB 模式,因此不需要 IV。也许它的存在会干扰正确的加密。是否存在不需要iv 参数的mcrypt_encrypt() 函数的另一个版本,或者您可以传递null0 或任何PHP 等效的“未定义”来代替生成IV?跨度>
  • @Redth - 我自己做了一些测试(在 Java 中),当使用 16 字节密钥时,我得到了与您的 .NET 相同的结果。此外,如果我按照描述创建一个 24 字节密钥(将最后 8 个字节设置为前 8 个字节),我会得到相同的密文结果(我的结果不会改变)。听起来您是在说如果您自己创建 24 字节密钥,您的 .NET 代码会产生不同的结果。那么密文是什么呢?而且,当你在 PHP 中创建 24 字节的密钥时,你的密文是什么?
【解决方案2】:

我找到了解决方案,请查看此链接,可能会对您有所帮助。 http://sanity-free.com/131/triple_des_between_php_and_csharp.html

这里是解密函数以防万一:

    public static string Decrypt(string cypherString)
    {

        byte[] key = Encoding.ASCII.GetBytes("icatalogDR0wSS@P6660juht");
        byte[] iv = Encoding.ASCII.GetBytes("iCatalog");
        byte[] data = Convert.FromBase64String(cypherString);
        byte[] enc = new byte[0];
        TripleDES tdes = TripleDES.Create();
        tdes.IV = iv;
        tdes.Key = key;
        tdes.Mode = CipherMode.CBC;
        tdes.Padding = PaddingMode.Zeros;
        ICryptoTransform ict = tdes.CreateDecryptor();
        enc = ict.TransformFinalBlock(data, 0, data.Length);
        return UTF8Encoding.UTF8.GetString(enc, 0, enc.Length);
    }

【讨论】:

    【解决方案3】:

    看看encoding.getBytes,你需要UTF8的秘钥Bytes...

    【讨论】:

      【解决方案4】:

      C# 版本似乎没有设置IV。如果您不知道它是什么,这可能是一个问题,因为 msdn 说:

      每当您创建 SymmetricAlgorithm 类之一的新实例或手动调用 GenerateIV 方法时,IV 属性都会自动设置为新的随机值。

      看起来在 PHP 版本中,您使用的是IV。您可以尝试不提供 IV,并希望 C# 版本也使用零。

      编辑:看起来对于 ECB,IV 被忽略了。

      您可能还需要像在 C# 版本中一样使用 utf8-encode 对密钥进行编码

      【讨论】:

      • 欧洲央行模式。没有 IV。
      猜你喜欢
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-17
      相关资源
      最近更新 更多