Dillz
Dillz

Reputation: 197

Converting a PHP encrypt code to Java show error?

I am creating an application which calls a third party API, they provided PHP code and what we require is a Java code.

The PHP code is given below:

function encryptIt( $string ) {
$key = 'qJB0rGtIn5UB1xG03efyCp';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
$encrypted = openssl_encrypt($string, 'aes-256-cbc', $key, 0, $iv);
return base64_encode($encrypted . '::' . $iv);
}

Now I changed the abouve code to java as:

private static String openssl_encrypt(String data, String strKey, String strIv) throws Exception {
        SecureRandom randomSecureRandom = new SecureRandom();
        Base64 base64 = new Base64();
        Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] ivv = new byte[ciper.getBlockSize()];
        randomSecureRandom.nextBytes(ivv);
        SecretKeySpec key = new SecretKeySpec(strKey.getBytes(), "AES");
        IvParameterSpec iv = new IvParameterSpec(ivv, 0, ciper.getBlockSize());

        // Encrypt
        ciper.init(Cipher.ENCRYPT_MODE, key, iv);
        byte[] encryptedCiperBytes = ciper.doFinal(data.getBytes());

        String s = new String(base64.encode(encryptedCiperBytes));
        System.out.println("Ciper : " + s);
        return s;
    }

Actually I am not good in encryption techniques so the PHP code creates a IV code but after searching in internet I tried to create a IV code as above,

But I got the error as:

java.security.InvalidKeyException: Invalid AES key length: 22 bytes
    at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:509)
    at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1067)
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1038)
    at javax.crypto.Cipher.init(Cipher.java:1393)
    at javax.crypto.Cipher.init(Cipher.java:1327)

Please help me to solve this

UPDATED:

I updated the code to :

private static String openssl_encrypt(String data) throws Exception {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);
        KeySpec spec = new PBEKeySpec("qJB0rGtIn5UB1xG03efyCp".toCharArray(), salt, 65536, 256); // AES-256
        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        byte[] key = f.generateSecret(spec).getEncoded();
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

        byte[] ivBytes = new byte[16];
        random.nextBytes(ivBytes);
        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.ENCRYPT_MODE, keySpec, iv);
        byte[] encValue = c.doFinal(data.getBytes());

        byte[] finalCiphertext = new byte[encValue.length+2*16];
        System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
        System.arraycopy(salt, 0, finalCiphertext, 16, 16);
        System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);
        String s = new String(Base64.getEncoder().encodeToString(finalCiphertext));
        return s;
    }

Still i got the error as :

java.security.InvalidKeyException: Illegal key size

My API providers says that thats the key!

Upvotes: 2

Views: 298

Answers (1)

Maarten Bodewes
Maarten Bodewes

Reputation: 93968

Just like the ill-fated mcrypt crap, openssl_encrypt allows incorrectly sized keys. Instead of rejecting such keys, it simply fills the rest of the key with zero valued bytes ("\0" in PHP). This is completely against any good cryptographic practice, by almost any library for higher level languages.

This is very likely due to two reasons:

  • C, which commonly expects a pointer to a key, for which the size is predetermined (hence the -256 in the openssl commands).
  • PHP, having dynamic variable typing, making users expect functions to accept any kind of crap variable type or state.

To copy the flawed PHP code you therefore have to pad the key with zero bytes (until the array is 32 bytes long). In Java, that's commonly performed using the horrible Arrays.copyOf nowadays (as it also right-pads zero bytes).

Note that the IV will of course still make sure that your encryption results never match. Instead, try to decrypt in Java and use the same scheme for encryption, making sure the IV stays random in the final code.


Keys are never strings. Keys consist of bits or - preferably - references to keys stored somewhere in secure memory. Passwords are strings however, and using PKBDF2 should indeed be preferred.

Of course, to use PBKDF2 it is required to:

  1. need to do the same thing in your PHP code and
  2. make sure you either use an up-to-data Java environment (strongly preferred for secure environments), or install the unlimited jurisdiction policy files in your Java runtime environment.

Upvotes: 3

Related Questions