我尝试使用以下代码在JAVA中解密一个加密的字符串。
SecretKey secretKey = new SecretKeySpec(build3DesKey(key), "DESede"); Cipher cipher = Cipher.getInstance("DESede"); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] b = cipher.doFinal(str2ByteArray(dest)); String decoder = new String(b, "utf-8");
private static byte[] build3DesKey(String keyStr) throws Exception { byte[] key = new byte[24]; byte[] temp = keyStr.getBytes("utf-8"); if (key.length > temp.length) { System.arraycopy(temp, 0, key, 0, temp.length); } else { System.arraycopy(temp, 0, key, 0, key.length); } return key; }
我如何在PHP版本中获得相同的结果?我尝试用PHP写,但输出的结果是错误的。
$data = '69C16E8142F2BDDE7569842BB0D68A3176624264E...'; $key = 'rpwdvbppnrvr56m123+#'; function decrypt($data, $secret) { //从哈希生成密钥 $key = md5(utf8_encode($secret), true); //将$key的前8个字节附加到$key的末尾。 $key .= substr($key, 0, 8); $data = base64_decode($data); $data = mcrypt_decrypt('tripledes', $key, $data, 'ecb'); $block = mcrypt_get_block_size('tripledes', 'ecb'); $len = strlen($data); $pad = ord($data[$len-1]); return substr($data, 0, strlen($data) - $pad); } var_dump(utf8_encode(Decrypt($data, $key)));
函数
build3DesKey()
将一个太短的3DES密钥扩展到24个字节,通过在末尾填充0x00值,对于太长的密钥,末尾会被简单地截断。在PHP中,可以如下实现build3DesKey()
:尽管缺少函数
str2ByteArray()
,但其功能可以推断出来。由于在您的示例中,密文是十六进制编码的,所以这个函数似乎只是执行十六进制解码。在PHP中,与str2ByteArray()
相对应的是hex2bin()
。因此,解密的可能实现方式是(使用PHP/OpenSSL):
rrreee这些输入数据在Java代码中返回相同的明文!
与您的代码的差异:
您的代码使用了已弃用的
mcrypt
。出于安全原因,现在不应该使用它。一个更好的替代方案是PHP/OpenSSL,如上面的代码所示。此外,实现的密钥派生是错误的,例如它应用了MD5摘要,在Java代码中根本没有使用。安全性:
尽管这可能是一个旧的应用程序,但还是有几点关于安全性的说明:
build3DesKey()
是不安全的。如果密钥材料是一个字符串,它通常不是一个密钥,而是一个密码。因此,应该使用可靠的密钥派生函数,例如Argon2或PBKDF2。