0

I need to do something like this in Java

function my_simple_crypt( $string) 
{
    global $secret_key, $secret_iv;

    $output = false;
    $encrypt_method = "AES-256-CBC";
    $key = hash( 'sha256', $secret_key );
    $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );

    $output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );

    return $output;
}

I know the string that is an hash code containing some informations, I know the secret_key and the secret_iv (both are strings).

I tried with many examples here on SO, but no-one is working properly.

I tried to do it from myself. But I need a function that do the openssl_decrypt. This is my code for now:

final String secretKey = "****";
final String secretIv = "****";

final String decryptedString = decrypt(decodedHashCode, secretKey, secretIv);

I'm trying to write the decrypt function.

I wrote this:

private String decrypt(final String hashCode, final String key, final String iv) throws Exception
{
    InputStream cipherInputStream = null;
    try
    {
        final StringBuilder output = new StringBuilder();
        final byte[] secretKey = DigestUtils.sha256Hex(key).getBytes();
        final byte[] initVector = DigestUtils.sha256Hex(iv).substring(0, 16).getBytes();
        final byte[] decodedBytes = Base64.getDecoder().decode(hashCode);
        final String decodedString = new String(decodedBytes);
        final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey, "AES"),
                new IvParameterSpec(initVector, 0, cipher.getBlockSize()));
        cipherInputStream = new CipherInputStream(new FileInputStream(decodedString), cipher);

        final String charsetName = "UTF-8";

        final byte[] buffer = new byte[8192];
        int read = cipherInputStream.read(buffer);

        while (read > -1)
        {
            output.append(new String(buffer, 0, read, charsetName));
            read = cipherInputStream.read(buffer);
        }

        System.out.println(output);
        return output.toString();
    }
    finally
    {
        if (cipherInputStream != null)
        {
            cipherInputStream.close();
        }
    }

}

but I get an error during the cipher initialization. The error is: java.security.InvalidKeyException: Invalid AES key length: 64 bytes

How can I do this in Java?

sharkbait
  • 2,980
  • 16
  • 51
  • 89
  • 1
    Please, check this post: https://stackoverflow.com/questions/15594518/using-java-to-decrypt-openssl-aes-256-cbc-using-provided-key-and-iv – Ansemo Abadía Sep 12 '18 at 16:42
  • 1
    Sorry, but your PHP code is not that good. a) It uses static key and IV. b) Uses SH256 as a KDF. c) The output of `hash` is hex encoded by default, so your key is 64 bytes long and contains only a-f0-9 characters. d) It doesn't use authentication, which can be very bad with CBC. – t.m.adam Sep 12 '18 at 17:18
  • @t.m.adam see my edits! – sharkbait Sep 13 '18 at 08:47
  • AES uses binary keys for propper encryption, not passwords. The problem with passwords is that they usually don't have enouff entropy and needs some password stretching etc. to get to a propper key. If you use a password, you should use a propper [Key derivation function](https://en.wikipedia.org/wiki/Key_derivation_function), not a SHA256 .. this way you also don't need to figure out how to get a key of the right length from the SHA256 - this seems to be your problem right now. – Ebbe M. Pedersen Sep 13 '18 at 11:07
  • yes but I need to implement the same thing as in php... I don't know how to do it – sharkbait Sep 13 '18 at 11:48
  • 1
    I'd be happy to help with your Java code, if you fix those issues I mentioned. You'll have to use a CSPRNG for the IV ([`openssl_random_pseudo_bytes`](http://php.net/manual/en/function.openssl-random-pseudo-bytes.php) and [`SecureRandom`](https://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html)). The IV doesn't have to be secret, you could store it with the ciphertext. It's a common practice to concatenate IV + ciphertext. – t.m.adam Sep 13 '18 at 12:31
  • 1
    I suppose you could get a 32 byte key from SH256 if you don't hex-encode it but it's best to use PBKDF2 ([`openssl_pbkdf2`](http://php.net/manual/en/function.openssl-pbkdf2.php), [`SecretKeyFactory`](https://docs.oracle.com/javase/8/docs/api/index.html?javax/crypto/SecretKeyFactory.html)). If you're using the latest version of PHP and Java, you could choose an AEAD algorithm. If not, you could use HMAC for authentication. You could also use a mode that doesn't require padding, but either way it's best to verify your data. – t.m.adam Sep 13 '18 at 12:36
  • Thank you @t.m.adam but could you please write the code as you're saying? I don't understand very well what I have to change in my Java code. – sharkbait Sep 14 '18 at 08:04
  • But the problem is with the PHP code, it's not very safe to encrypt data with this code. I could help with the Java part, if you could improve your PHP code - just implement what I've mentioned in previous comments. – t.m.adam Sep 14 '18 at 14:07

0 Answers0