C# 和 PHP 中的 TripleDES 加密结果不一样(PKCS7、ECB)?
我现在花了几个小时试图解决这个问题,但我就是无法让它发挥作用。我有一个 C# 加密例程,需要在 php.ini 中进行匹配。我无法更改 C# 版本,这不是一个选项(第 3 方对此很坚定)。
这是 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 上,不确定这是否会产生影响。
I've spent a couple hours now trying to figure this out, but I just can't get it to work. I've got a C# encryption routine that I need to match in php. I can't change the C# version, that's not an option (3rd party is firm on this).
Here's the C# code:
//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);
}
Here's the best of what I've come up with in 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);
}
To the best of my knowledge, I'm handling the PKCS7 padding properly on the PHP side. I'm not sure what else to try.
One thing to note, the C# is happening on windows, and the PHP on linux, not sure that should make a difference.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
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()
。The padding length in your PHP version is based on the length of the password. This is incorrect. It should be based on the length of your message instead.
Try replacing
strlen($password)
withstrlen($data)
.The second problem is that the
mcrypt
library requires 24-byte keys. Triple DES applies regular DES three times, so you can call the 8-byte key used in each round of DES K1, K2, and K3. There are different ways to choose these keys. The most secure is to choose three distinct keys. Another way is to set K3 equal to K1. The least secure method (equivalent to DES) is to make K1 = K2 = K3.Most libraries are "smart" enough to interpret a 16-byte 3DES key as the second option above: K3 = K1. The .NET implementation is doing this for you, but the
mcrypt
library is not; instead, it's setting K3 = 0. You'll need to fix this yourself, and passmcrypt
a 24-byte key.After computing the MD5 hash, take the first 8 bytes of
$key
, and append them to the end of$key
, so that you have a 24-byte value to pass tomcrypt_encrypt()
.我找到了解决方案,请查看此链接,可能会对您有所帮助。 http://sanity-free.com/131/triple_des_ Between_php_and_csharp.html
这是解密函数以防万一:
I found a solution, check this link, may help you. http://sanity-free.com/131/triple_des_between_php_and_csharp.html
And here is the decrypt function just in case:
看看encoding.getBytes,你需要来自UTF8的秘密密钥Bytes...
Take a look at encoding.getBytes, you need the secret key Bytes from UTF8...
C# 版本似乎未设置IV.如果您不知道这是什么,这可能是一个问题,因为 msdn 说:看起来在 PHP 版本中,您正在使用 IV。您可以尝试不提供 IV,并希望 C# 版本也使用零。编辑:看起来对于 ECB,IV 被忽略。
您可能还需要像 C# 版本中那样使用 utf8-encode
It appears the C# version does not set the IV. This could be an issue if you dont know what it is because msdn says:It looks like in the PHP version, you are using an IV. You could try not supplying the IV and hope the C# version also uses zeros.Edit: Looks like for ECB, the IV is ignored.
You might also need to encoding the key like in the C# version using utf8-encode