繁体   English   中英

如何解密在 Java 中加密的 PHP 中的字符串?

[英]How to decrypt a string in PHP that was encrypted in Java?

我试图用下面的代码解密 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)
{
    //Generate a key from a hash
    $key = md5(utf8_encode($secret), true);
    //Take first 8 bytes of $key and append them to the end of $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() function 通过用 0x00 值填充结尾将太短的 3DES 密钥扩展为 24 个字节,对于太长的密钥,结尾被简单地截断。 build3DesKey()可以在 PHP 中实现如下:

$key = substr(str_pad($key, 24, "\0"), 0, 24);

虽然缺少str2ByteArray() function,但可以推断出它的功能。 由于在您的示例中密文是十六进制编码的,因此此 function 似乎只是执行十六进制解码。 在 PHP 中, str2ByteArray()的模拟是hex2bin()

因此,一个可能的解密实现是(使用 PHP/OpenSSL):

$key = "12345";
$ciphertext = "84b24172c57752385251d142abadbed1d9945301a3aee429ce00c1e291a605c30ad18c5e00007f6db394fc6138a2ee4c";
$key = substr(str_pad($key, 24, "\0"), 0, 24);
$plaintext = openssl_decrypt(hex2bin($ciphertext), "des-ede3", $key, OPENSSL_RAW_DATA);
print($plaintext. PHP_EOL); // The quick brown fox jumps over the lazy dog

Java 代码为这些输入数据返回相同的纯文本!


与您的代码的差异:
您的代码使用已弃用的mcrypt 出于安全原因,现在不应应用此方法。 更好的替代方案是 PHP/OpenSSL,它在上面的代码中使用。 此外,实现的密钥派生是错误的,例如它应用了摘要 MD5,而 Java 代码中根本没有使用它。


安全:
尽管这可能是一个遗留应用程序,但关于安全性的几句话:

  • 密钥派生build3DesKey()是不安全的。 如果密钥材料是字符串,一般不是密钥,而是密码。 因此,应使用可靠的密钥派生 function,例如 Argon2 或 PBKDF2。
  • des-ede3 应用 ECB 模式,这也是不安全的。 现在应该使用经过身份验证的加密,例如 AES-GCM。
  • 3DES/TripleDES 已过时,唯一尚未弃用的变体、三重长度密钥或 3TDEA 将很快推出,而且速度相对较慢。 今天的标准AES应该在这里应用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM