openssl encrpyt java decrypt

59 Views Asked by At

Hello I am using openssl to encrypt a string and JAVA code to decrypt it. My key is "SUDIPTA123". The command I am using to encrypt

encdata=$(echo -n "12345627678" | openssl enc -v -aes-256-cbc -base64 -nosalt -pass "pass:$key")

encdata contains /oUakLZnim7aPtpRySLRDw==.

Now I am using the follwoing JAVA code to decrypt encdata

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.KeySpec;
import java.util.Base64;

public class AESDecryptor {
    public static void main(String[] args) {
        String encryptedText = "/oUakLZnim7aPtpRySLRDw==";
        String password = "SUDIPTA123";

        try {
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
            byte[] ivBytes = new byte[16];
            System.arraycopy(encryptedBytes, 0, ivBytes, 0, 16);
            byte[] encryptedData = new byte[encryptedBytes.length - 16];
            System.arraycopy(encryptedBytes, 16, encryptedData, 0, encryptedData.length);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec spec = new PBEKeySpec(password.toCharArray(), ivBytes, 65536, 256);
            SecretKeySpec secretKeySpec = new 
            SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(ivBytes));

            byte[] decryptedData = cipher.doFinal(encryptedData);

            String decryptedText = new String(decryptedData, "UTF-8");
            System.out.println("Decrypted Text: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

After running the code decryptedText is empty string. I am not sure what I am doing wrong. Any help would be appreciated.

1

There are 1 best solutions below

0
Topaco On

Decryption fails because OpenSSL statement and Java code apply different key derivation functions (KDFs): In the OpenSSL statement the default EVP_BytesToKey() is used, in the Java code PBKDF2.
In order for both codes to be compatible, the same KDF must be applied, i.e. if the OpenSSL statement is the reference, EVP_BytesToKey() must be used in the Java code.
There are various Java implementations on the web for EVP_BytesToKey(), e.g. the one from BouncyCastle.
Your decryption works if you replace the key and IV derivation part in your Java code, i.e. the complete first block inside the try {}, with (using BouncyCastle):

import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
...
byte[] encryptedData = Base64.getDecoder().decode(encryptedText); // no separation required (since OpenSSL does not concatenate IV and cipertext)
byte[] passwordBytes = password.getBytes("UTF-8");
OpenSSLPBEParametersGenerator pbeGenerator = new OpenSSLPBEParametersGenerator(new SHA256Digest()); // SHA256 as of v1.1.0 (if in OpenSSL the default digest is applied)
pbeGenerator.init(passwordBytes, new byte[0]); // no salt (as you did not apply a salt in the OpenSSL statement)
ParametersWithIV parameters = (ParametersWithIV) pbeGenerator.generateDerivedParameters(256, 128); // 32 bytes key, 16 bytes IV
KeyParameter keyParam = (KeyParameter)parameters.getParameters();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyParam.getKey(), "AES");
byte[] ivBytes = parameters.getIV();
...

Security:

  • EVP_BytesToKey() is deprecated (since insecure) and should no longer be used. Reliable key derivation functions are Argon2 or at least PBKDF2. The latter is also supported by more modern OpenSSL versions (via the -pbkdf2 and -iter options).
    In the context of PBKDF2, use an iteration count that is as large as possible with acceptable performance (usually a few 100000).
  • A key derivation without salt is insecure. To use a salt in your OpenSSL statement, remove the -nosalt option. Then, your OpenSSL statement returns the Base64 encoding of the ASCII encoding of Salted__, followed by an 8 bytes salt and the actual ciphertext.
    The salt and ciphertext must be separated during decryption. Afterwards, key and IV can be derived with passphrase and salt, and finally the actual ciphertext can be decrypted with the derived key and IV.