Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm not a cryptography profi and specially due to the fact that OpenSSL has lots of missing documentation, I'm not sure how can I solve this problem.

I have an external system which expects to receive encrypted messages. The only example provided uses OpenSSL in this way:

$ openssl enc -aes-256-cbc -a -in t.txt -k testpass
U2FsdGVkX1/RUdaSJKRXhHv3zUyTsQwu5/ar2ECKDlrNyH5GL4xRR4fgxkiWqkS1
cQstcoSIgWfRPSOFj/5OtdNLeNXiVR6MxSKJ+NvS9LyUD8+Rg6XIcYUvxR4gHi3w
DWT44LAMCpRAh1Q0t4Z2g7rwb0D05T6ygLaWvB5zD/xGZD3brTqSlWmiJb9Imgda
M6soZO7BhbYdqWqEUl5r6+EbkD21f6L3NX3hJFo+BJ+VFctiAlBO8NwT5l4ogo/s
GErm8gqRr57XoX/kvKAimg==

Where the t.txt file contains this string on one line:

AMOUNT=10&TID=#19:23&CURRENCY=EUR&LANGUAGE=DE&SUCCESS_URL=http://some.url/sucess&ERROR_URL=http://some.url/error&CONFIRMATION_URL=http://some.url/confirm&NAME=customer full name`

I have found this other question and I have been able to do the encryption using following code:

String password = "passPhrase";
String salt = "15charRandomSalt";
int iterations = 100;
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(Charset.forName("UTF8")), iterations, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] cipherText = cipher.doFinal(toBeEncrypted.getBytes("UTF-8"));
encryptedData = Base64.getEncoder().encodeToString(cipherText);
encryptedData += Base64.getEncoder().encodeToString(iv);

What I can not understand is how should I generate similar output (encryptedData) to what OpenSSL does. I have the salt, iv and cipherText, is the OpenSSL output Base64 encoded result of a concatenation of these? or only one single of them?

The only thing I share with that other system before encryption is the pass phrase. How could they decrypt the result if salt and number of iterations is not known to them?

Can somebody give answers to those unknown parameters and also tell me if the above code is the equivalent of OpenSSL process?

OpenSSL commandline enc does PBE by default, but you can do "raw" encryption with -K (must be uppercase) and -iv (if applicable), see the man page. OpenSSL library provides ciphers and PBKDFs separately and a program can use as desired. – dave_thompson_085 Sep 10, 2015 at 21:59 Also if you (can) use the BouncyCastle.org third-party provider it has already-written JCA keyfactory and Cipher for each of PBEWITHMD5AND{128,192,256}BITAES-CBC-OPENSSL . You still have to do the file-header and base64. – dave_thompson_085 Sep 10, 2015 at 22:06 what I dont need to do is to alter the OpenSSL process. I actually have to rebuild just the same process in java. I will take a look at BouncyCastle.org API. – mohamnag Sep 11, 2015 at 7:29

This question has an accepted answer which is a bit old, however this seems to be something that comes up again and again. I have 2 projects were we communicate with 3rd parties and the cipher is OpenSSL AES with a pre-shared key.

I have used the not-yet-common-ssl library. However it appears to be stuck at version 0.3.x and with no releases in almost 2 years, not any mailing list traffic or visible development I have to conclude that this is essentially dead.

Based on some additional stackoverflow questions I did find both Spring Security and Encryptor4j both of which seem to offer some reasonably packaged text encoding. However attempting to get Spring Security's Encryptors to work at decoding a known encoded text string failed for me, I am guessing that the IV and Key generation used by OpenSSL are simply not supported in the supplied implementation.

By examining the code above, as well as a known working C# and PHP implementation, I was able to come up with a utility class that is currently passing my tests for interoperability. Generally I'd greatly prefer to use a known library, but if there is one I have been unable to locate it. The class (https://gist.github.com/rrsIPOV/4d0f6be7c58173c16e9edf9f97c7d7f2) is as follows:

import groovy.transform.CompileStatic;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.SecureRandom;
import static java.nio.charset.StandardCharsets.*
* Mimics the OpenSSL AES Cipher options for encrypting and decrypting messages using a shared key (aka password) with symetric ciphers.
@CompileStatic
class OpenSslAes {
/** OpenSSL's magic initial bytes. */
private static final String SALTED_STR = "Salted__";
private static final byte[] SALTED_MAGIC = SALTED_STR.getBytes(US_ASCII);
static String encryptAndURLEncode(String password, String clearText) {
    String encrypted = encrypt(password, clearText);
    return URLEncoder.encode(encrypted, UTF_8.name() );
 * @param password  The password / key to encrypt with.
 * @param data      The data to encrypt
 * @return  A base64 encoded string containing the encrypted data.
static String encrypt(String password, String clearText) {
    final byte[] pass = password.getBytes(US_ASCII);
    final byte[] salt = (new SecureRandom()).generateSeed(8);
    final byte[] inBytes = clearText.getBytes(UTF_8);
    final byte[] passAndSalt = array_concat(pass, salt);
    byte[] hash = new byte[0];
    byte[] keyAndIv = new byte[0];
    for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
        final byte[] hashData = array_concat(hash, passAndSalt);
        final MessageDigest md = MessageDigest.getInstance("MD5");
        hash = md.digest(hashData);
        keyAndIv = array_concat(keyAndIv, hash);
    final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
    final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
    final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
    final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
    byte[] data = cipher.doFinal(inBytes);
    data =  array_concat(array_concat(SALTED_MAGIC, salt), data);
    return Base64.getEncoder().encodeToString( data );
 * @see http://stackoverflow.com/questions/32508961/java-equivalent-of-an-openssl-aes-cbc-encryption  for what looks like a useful answer.  The not-yet-commons-ssl also has an implementation
 * @param password
 * @param source The encrypted data
 * @return
static String decrypt(String password, String source) {
    final byte[] pass = password.getBytes(US_ASCII);
    final byte[] inBytes = Base64.getDecoder().decode(source);
    final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0, SALTED_MAGIC.length);
    if (!Arrays.equals(shouldBeMagic, SALTED_MAGIC)) {
        throw new IllegalArgumentException("Initial bytes from input do not match OpenSSL SALTED_MAGIC salt value.");
    final byte[] salt = Arrays.copyOfRange(inBytes, SALTED_MAGIC.length, SALTED_MAGIC.length + 8);
    final byte[] passAndSalt = array_concat(pass, salt);
    byte[] hash = new byte[0];
    byte[] keyAndIv = new byte[0];
    for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
        final byte[] hashData = array_concat(hash, passAndSalt);
        final MessageDigest md = MessageDigest.getInstance("MD5");
        hash = md.digest(hashData);
        keyAndIv = array_concat(keyAndIv, hash);
    final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
    final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
    final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
    final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
    final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
    return new String(clear, UTF_8);
private static byte[] array_concat(final byte[] a, final byte[] b) {
    final byte[] c = new byte[a.length + b.length];
    System.arraycopy(a, 0, c, 0, a.length);
    System.arraycopy(b, 0, c, a.length, b.length);
    return c;
                Thank you for the complete solution. This was extremely helpful. I had to downgrade it to java 7 so the Base64 stuff was converted to user the answer from stackoverflow.com/questions/14413169/….  That will help others who are using older versions of Java
– Rob
                Apr 4, 2017 at 16:07
                your code is extremely helpful. I had copy your code and enhance it to support for ECB mode, 128 and 256 bit AES, with and without PBKDF2 and it is available here: gist.github.com/thiamteck/798343b9e4a5d7df748746d995eba53e
– ThiamTeck
                Nov 8, 2020 at 7:16

Following is a Java program to decrypt the above OPENSSL encryption (it requires Java 8):

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Base64;
import java.util.Base64.Decoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class TestAesDecrypt {
    public static void main(final String[] args) throws Exception {
        final byte[] pass = "testpass".getBytes(StandardCharsets.US_ASCII);
        final byte[] magic = "Salted__".getBytes(StandardCharsets.US_ASCII);
        final String inFile = "e:/t/e.txt";
        String source = new String(Files.readAllBytes(Paths.get(inFile)),
                StandardCharsets.US_ASCII);
        source = source.replaceAll("\\s", "");
        final Decoder decoder = Base64.getDecoder();
        final byte[] inBytes = decoder.decode(source);
        final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0,
                magic.length);
        if (!Arrays.equals(shouldBeMagic, magic)) {
            System.out.println("Bad magic number");
            return;
        final byte[] salt = Arrays.copyOfRange(inBytes, magic.length,
                magic.length + 8);
        final byte[] passAndSalt = concat(pass, salt);
        byte[] hash = new byte[0];
        byte[] keyAndIv = new byte[0];
        for (int i = 0; i < 3; i++) {
            final byte[] data = concat(hash, passAndSalt);
            final MessageDigest md = MessageDigest.getInstance("MD5");
            hash = md.digest(data);
            keyAndIv = concat(keyAndIv, hash);
        final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
        final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
        final String clearText = new String(clear, StandardCharsets.ISO_8859_1);
        System.out.println(clearText);
    private static byte[] concat(final byte[] a, final byte[] b) {
        final byte[] c = new byte[a.length + b.length];
        System.arraycopy(a, 0, c, 0, a.length);
        System.arraycopy(b, 0, c, a.length, b.length);
        return c;
                I was actually looking for encryption (openSSL equivalent) in Java, but based on your answer I was able to produce the procedure, so I will mark it as answer.
– mohamnag
                Oct 2, 2015 at 20:02
                @mohamnag  - I don't suppose that you would consider sharing your encryption code?  I have found some additional older implementations, but it would be handy to have this as part of the answer.
– Robert
                Jan 3, 2017 at 22:42
                @Robert the problem with my code was that it was specifically designed for a very limited type of input and it was anyway replaced with a library provided by 3rd party later on. I think encryption code should be really throughly tested an therefore it is not probably a good idea to share a half way used code
– mohamnag
                Jan 4, 2017 at 9:48
                Hi, i used the above encrypt method to redirect encrypted data to a file in java. password is "testpass".   But when i decrypt it using openssl command i get "bad magic number" error. Here is the command: "openssl aes-256-cbc -d -in input.crypt -out output.txt -k testpass"  Please suggest if the command is wrong. im also little confused on how to add the salt in the command.
– Anees U
                Oct 19, 2020 at 7:24

You may look at this discussion specifying the key generation algorithm as the concatenation of two MD5 hashes.

Regarding the salt mentioned there, the opensssl enc man page says:

When the salt is being used the first eight bytes of the encrypted data are reserved for the salt: it is generated at random when encrypting a file and read from the encrypted file when it is decrypted.

And after generating the key and IV (for CBC), and encrypting the plaintext with them, -a base64 encodes the ciphertext. – dave_thompson_085 Sep 10, 2015 at 22:01 Is it necessary that I write the key generation algorithm myself? I just added a piece of code to question which probably should do all the encryption process correctly however what I'm missing is how to build that base64 encoded output out of salt, IV and ciphered text. – mohamnag Sep 11, 2015 at 7:49

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.