将TripleDESCryptoServiceProvider从C#移植到PHP

时间:2017-10-18 08:01:55

标签: c# php encryption mcrypt tripledes

我试图将以下C#方法移植到PHP,但我无法正确输出。

public static string Encrypt()
{
      String text = "123456";
      String key = "1r1ppl3x";
      byte[] arrText = UTF8Encoding.UTF8.GetBytes(text);
      TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
      tdes.Key = (new UnicodeEncoding()).GetBytes(key);
      tdes.Mode = CipherMode.ECB;
      tdes.Padding = PaddingMode.PKCS7;
      ICryptoTransform cTransform = tdes.CreateEncryptor();
      byte[] resultArray = cTransform.TransformFinalBlock(arrText, 0, arrText.Length);
      tdes.Clear();
      String encrypted = Convert.ToBase64String(resultArray, 0, resultArray.Length);
      return encrypted;


}

到目前为止我在PHP中的尝试:

function encrypt()
{
    $key = utf8_encode("1r1ppl3x\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
    $data = utf8_encode("123456"); 
    $blocksize = mcrypt_get_block_size(MCRYPT_TRIPLEDES, MCRYPT_MODE_ECB);
    $tripleKey = substr($key, 0, mcrypt_get_key_size(MCRYPT_TRIPLEDES, MCRYPT_MODE_ECB));
    $paddingSize = $blocksize - (strlen($data) % $blocksize); 
    $data .= str_repeat(chr($paddingSize), $paddingSize);
    $encodedText = mcrypt_encrypt(MCRYPT_TRIPLEDES, $tripleKey, $data, MCRYPT_MODE_ECB);
    return base64_encode($encodedText);
}

由于某种原因,我无法获得与C#中相同的PHP代码输出。

此外,我知道在PHP 7.1中不推荐使用mcrypt_get_block_size和其他mcrypt相关方法,因此不建议使用它。

2 个答案:

答案 0 :(得分:2)

tdes.Key = (new UnicodeEncoding()).GetBytes(key);

UnicodeEncoding构造函数用于UTF-16,little-endian,“with BOM”。 “with BOM”并不重要,因为没有任何名为GetPreamble(),所以对于所有意图和目的,它都是UTF-16LE。

这意味着您的密钥("1r1ppl3x")实际上是:

31 00 72 00 31 00 70 00 70 00 6C 00 33 00 78 00

哪个是带有

的2DEA密钥
  • k1 = { 31 00 72 00 31 00 70 00 }
  • k2 = { 70 00 6C 00 33 00 78 00 }

哪个是非法的。除了.NET之外,.NET不关心DES奇偶校验位,所以它只是假装每个字节的最低有效位是正确的。无论PHP中的哪个库都可能都这样做。如果没有,您可能需要correct the parity manually

2DEA密钥的等效3DEA密钥为k3 = k1。因此,如果您的PHP库不支持2DEA密钥,您可以通过将前8个字节复制到结尾,人为地扩展它(在正确使用UTF-16LE而不是UTF-8之后),构建一个24字节的值。

如果utf8_encode是PHP中最好的“将文本转换为二进制数据”,那么您希望使用输入字符串"1\0r\01\0p\0p\0l\03\0x\01\0r\01\0p\0"

看起来您已找到How to add/remove PKCS7 padding from an AES encrypted string?,因此更正密钥会使您进入“等效功能”状态。

现在你所有的问题都在于你使用的是56位密钥(所有这些零都很容易猜到),好像它是一个168位的密钥,使用ECB模式,并使用一个已弃用的库,以及(可以说)你正在使用3DES而不是AES,并且(个人意见)从强类型语言转变为脚本语言。

答案 1 :(得分:0)

  1. C#代码使用PKCS#7填充,PHP MCRYPT代码使用空填充。

  2. 假设密钥应该使用空值扩展。

  3. 使用具有8字节的单个DES密钥的Triple DES是没有意义的。此外,仅使用56位的8位DES密钥。 56位密钥不被认为是安全的。