C#和PHP中的TripleDES加密不一样(PKCS7,ECB)?

我花了几个小时试图解决这个问题,但我无法让它发挥作用。 我有一个C#加密例程,我需要在php中匹配。 我不能改变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上,而Linux上发生的PHP,并不确定它是否应该有所作为。

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

尝试用strlen($password) strlen($data)替换strlen($password) strlen($data)


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

大多数库都“足够智能”,足以将16字节的3DES键解释为上面的第二个选项:K 3 = K 1 。 .NET实现正在为您执行此操作,但mcrypt库不是; 相反,它设置K 3 = 0.您需要自己修复此问题,并将mcrypt传递给一个24字节的密钥。

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

我找到了解决方案,查看此链接,可能会对您有所帮助。 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); } 

看一下encoding.getBytes,你需要来自UTF8的密钥字节…

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

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

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

编辑:对于ECB,IV被忽略。

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