0

For a project, I have to translate in Java the PHP fonctions openssl_decrypt and openssl_encrypt.

The PHP fonctions are called like that :

$cryptedValue = openssl_encrypt($dataSet[$cryptedFieldName], $this->getCryptOption('method'), $this->getCryptOption('hash'), false, $this->getCryptOption('vector'));

or :

$uncryptedValue = openssl_decrypt($dataSet[$cryptedFieldName], $this->getCryptOption('method'), $this->getCryptOption('hash'), false, $this->getCryptOption('vector'));

with cryptedFieldName = the String to crypt or decrypt and :

'method' = 'aes-256-cfb'
'hash' = 'GzH7vYfW2mp4TZKFx2UKuFvk4nPWy6KZyPSALFePVsWZp8kHhqDHfheZEABB5FAUdYQzbL25sPU9PbjHVHw8QgR2E832rHPKu9bV2HRzxLFWXV85j6CSGMeGpLks9duv'
'vector' = 'zvChhBgQ16yCBghn'

So, I translated the previous PHP code into the following Java code :

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import java.nio.charset.Charset;
import java.lang.reflect.Field;

public class Cryptage_EAS {

    public String decrypt(String encryptedText, String salt, String hash, String vector) throws Exception {

        // Autoriser le cryptage EAS 256
        try {
            Field field = Class.forName("javax.crypto.JceSecurity").
            getDeclaredField("isRestricted");
            field.setAccessible(true);
            field.set(null, java.lang.Boolean.FALSE);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        // Set en tableau de byte des différentes entrées
        byte[] vectorBytes = vector.getBytes(Charset.forName("UTF-8"));
        byte[] saltBytes = salt.getBytes(Charset.forName("UTF-8"));
        byte[] encryptedTextBytes = Base64.decodeBase64(encryptedText);

        // Création de la clé
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(hash.toCharArray(), saltBytes, 1, 256);
        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        // Décryptage
        Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(vectorBytes));

        return new String(cipher.doFinal(encryptedTextBytes), "UTF-8");
    }

    public String encrypt(String textToCrypt, String salt, String hash, String vector) throws Exception {  

        // Autoriser le cryptage EAS 256
        try {
            Field field = Class.forName("javax.crypto.JceSecurity").
            getDeclaredField("isRestricted");
            field.setAccessible(true);
            field.set(null, java.lang.Boolean.FALSE);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        // Set en tableau de byte des différentes entrées
        byte[] vectorBytes = vector.getBytes(Charset.forName("UTF-8"));
        byte[] saltBytes = salt.getBytes(Charset.forName("UTF-8"));

        // Création de la clé
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(hash.toCharArray(), saltBytes, 1, 256);
        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        // Cryptage
        Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(vectorBytes));
        byte[] encryptedTextBytes = cipher.doFinal(textToCrypt.getBytes("UTF-8"));

        return new Base64().encodeAsString(encryptedTextBytes);
    }
}

For the main class :

Cryptage_EAS c_EAS = new Cryptage_EAS();
String hash = "GzH7vYfW2mp4TZKFx2UKuFvk4nPWy6KZyPSALFePVsWZp8kHhqDHfheZEABB5FAUdYQzbL25sPU9PbjHVHw8QgR2E832rHPKu9bV2HRzxLFWXV85j6CSGMeGpLks9duv";
String salt = "SelDeMerFin";
String vector = "zvChhBgQ16yCBghn";
String strToCrypt = "The Answer Is 42";
String encryptedText = c_EAS.encrypt(strToCrypt, salt, hash, vector);
System.out.println("Encrypted : "+c_EAS.encrypt(strToCrypt, salt, hash, vector));
System.out.println("Decrypted : "+c_EAS.decrypt(encryptedText, salt, hash, vector));

My Java code works but I am not sure that it corresponds exactly to what is coded behind openssl_decrypt and openssl_encrypt. For instance a salt is not needed in PHP but mandatory in my Java functions.

What do you think of my code ? Is it possible to add a Salt parameter in the PHP function ? Then, will it produce the same result ? My major question is finally : is my translation of the PHP functions seems to be correct for you and what am I supposed to do to my extra and mandatory extra salt parameter ? Thanks.

1 Answers1

0

I really don't know why you implemented PBKDF2 in Java. That's nowhere near what openssl_encrypt is doing. In fact, if you've read the first comment in the documentation, you should have seen that the pass parameter is actually the key and not some kind of password. You need to provide a 32 byte key to openssl_encrypt if you want AES-256 which will be the first 32 bytes of your "hash": "GzH7vYfW2mp4TZKFx2UKuFvk4nPWy6KZ"

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • Hi ! Thank you for your answer. For the PBKDF2 I don't know, I thought it was a sort of standard to crypt in AES256 : [link](http://karanbalkar.com/2014/02/tutorial-76-implement-aes-256-encryptiondecryption-using-java/) or [link](http://stackoverflow.com/questions/992019/java-256-bit-aes-password-based-encryption) what should I use instead ? Ok for the 32 bits hash, I don't know why the PHP developer took a long key like that. I am just here to translate this thing in Java... – Derfel Cadarn Nov 21 '15 at 12:42
  • Well, if you're encrypting with an actual password and not a randomly generated key, then it's a good idea to use PBKDF2 with a lot of iterations (more than 100,000) and a random salt (that can be put beside the ciphertext) to derive a key from a password. That's just not what is happening in your PHP code. I would strongly suggest that you look into changing the PHP code to use PBKDF2. – Artjom B. Nov 21 '15 at 12:55
  • Keep in mind that you should probably add authentication to your ciphertexts in order to detect (malicious) manipulations of the ciphertext in transit. If you can change the PHP code, then I can recommend [RNCryptor-php](https://github.com/RNCryptor/RNCryptor-php) which also has a [Java version (JNCryptor)](https://github.com/RNCryptor/JNCryptor) and should be compatible. – Artjom B. Nov 21 '15 at 13:18
  • Ok thanks for all. I guess I will have a discussion with the PHP developer... R/JNCryptor seems to be a good idea. We will be certain to have the same results. – Derfel Cadarn Nov 21 '15 at 13:29