Home > Blockchain >  How to decrypt a string in PHP that was encrypted in Java?
How to decrypt a string in PHP that was encrypted in Java?

Time:08-30

I tried to decrypt en encrypted string in JAVA with to code below.

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;
}

How can I get the same result with PHP version? I tried to write in PHP and It outputs with wrong result.

$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)));

CodePudding user response:

The build3DesKey() function expands a too short 3DES key to 24 bytes by padding the end with 0x00 values, for too long keys the end is simply truncated. build3DesKey() can be implemented in PHP as follows:

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

Although the str2ByteArray() function is missing, its functionality can be deduced. Since in your example the ciphertext is hexadecimal encoded, this function seems to simply perform a hex decoding. In PHP, the analog to str2ByteArray() is hex2bin().

Thus, a possible implementation for decryption is (using 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

The Java code returns the same plain text for these input data!


Differences to your code:
Your code uses the deprecated mcrypt. This should not be applied nowadays for security reasons. A better alternative is PHP/OpenSSL, which is used in the code above. Also, the implemented key derivation is wrong, e.g. it applies the digest MD5, which is not used in the Java code at all.


Security:
Even though this is probably a legacy application, a few words about security:

  • The key derivation build3DesKey() is insecure. If the key material is a string, it is generally not a key, but a password. Therefore a reliable key derivation function should be used, e.g. Argon2 or PBKDF2.
  • des-ede3 applies ECB mode, which is also insecure. Nowadays authenticated encryption, e.g. AES-GCM should be used.
  • 3DES/TripleDES is outdated and the only not yet deprecated variant, triple-length keys or 3TDEA will be soon, and is comparatively slow. Today's standard AES should be applied here.
  • Related