您遇到此问题是因为 Triple DES 的密钥大小为 168 位(21 字节),但 MD5 生成的哈希值只有 16 字节(128 位)长。
这意味着密钥必须扩展到 168 位,以便 Triple DES 可以工作。事实证明,这种从 128 位到 168 位的推导在 C# 中的工作方式与在 PHP 中的工作方式不同,因此有效使用的密钥不同,从而产生不同的加密数据。
现在你有两个选择:
选项 1:选择完全支持 128 位密钥的密码
如果您使用支持 128 位密钥的密码,则可以避免与密钥大小差异相关的所有问题。这将需要对您的代码进行最少的更改。例如,您可以使用 Rijndael (AES)。
C#: 改变TripleDESCryptoServiceProvider
to RijndaelManaged
.
其他一切都可以保持不变。(Demo) http://ideone.com/huPErj
PHP: Use MCRYPT_RIJNDAEL_128
而不是三元组(Demo) http://ideone.com/TEU3zr:
function encrypt_pkcs7($str, $key)
{
$key = md5(utf8_encode($key), true);
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$pad = $block - (strlen($str) % $block);
$str .= str_repeat(chr($pad), $pad);
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB);
return base64_encode($ciphertext);
}
echo encrypt_pkcs7('test', '123456');
请注意,AES 的有效密钥大小大于 Triple DES。虽然 Triple DES 的密钥是 168 位长,但它只提供 112 位的安全性。如果我是你,我会选择这个选项。
选项 2:使用 192 位密钥而不是 128 位密钥
如果您使用的密钥比 Triple DES 实际使用的密钥大,C# 和 PHP 似乎就如何将其减少到 168 位达成了一致。您可以使用 SHA-256 等哈希函数来实现此目的,该函数生成 256 位哈希并将其修剪为 192 位(24 字节):
C#: Use SHA256CryptoServiceProvider
and Array.Copy
获取 192 位密钥,并将其与程序的其余部分一起使用:(Demo) http://ideone.com/emTLD9
SHA256CryptoServiceProvider HashProvider = new SHA256CryptoServiceProvider();
byte[] temp = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));
byte[] key = new byte[24];
Array.Copy(temp, key, 24);
PHP: Use hash()
使用 SHA-256 和substr()
获取192位密钥
function encrypt_pkcs7($str, $key)
{
// derive 192-bit key using SHA-256
$key = substr(hash('sha256', $key, true), 0, 24);
$block = mcrypt_get_block_size(MCRYPT_3DES, MCRYPT_MODE_ECB);
$pad = $block - (strlen($str) % $block);
$str .= str_repeat(chr($pad), $pad);
$ciphertext = mcrypt_encrypt(MCRYPT_3DES, $key, $str, MCRYPT_MODE_ECB);
return base64_encode($ciphertext);
}
echo encrypt_pkcs7('test', '123456');
我似乎无法提供 168 位密钥TripleDESCryptoServiceProvider
,我不知道为什么。
其他考虑因素:
-
考虑使用 SSL;即使它是自签名证书。它胜过重新发明轮子,当涉及密码学时,这是一项特别危险的任务。
-
考虑使用 ECB 以外的操作模式(例如:CBC)。使用 ECB 会增加安全风险。阅读维基百科关于分组密码操作模式的文章 http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation.
-
除非你绝对地需要有一个明文密码(很少有这种情况),您应该对密码进行哈希处理。读这篇关于保护密码的文章。 http://crackstation.net/hashing-security.htm
-
考虑使用适当的基于密码的密钥派生函数,例如PBKDF2 http://en.wikipedia.org/wiki/PBKDF2而不是 MD5 或 SHA 系列等通用哈希函数。这将使破解密钥变得更加困难。有关更多信息,请阅读上一个要点中的文章。