How to decrypt file in Java encrypted with openssl command using AES?

Viewed 25775

I need to decrypt in JAVA a file encrypted in UNIX with the following command:

openssl aes-256-cbc -a -salt -in password.txt -out password.txt.enc
mypass
mypass

I have to decrypt in java as I do here I do in UNIX

openssl aes-256-cbc -d -a -in password.txt.enc -out password.txt.new
mypass

Someone can give me a java code to do this?

4 Answers

In Kotlin:

package io.matthewnelson.java_crypto

import java.util.*
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec

class OpenSSL {

    /**
     * Will decrypt a string value encrypted by OpenSSL v 1.1.1+ using the following cmds from terminal:
     *
     *   echo "Hello World!" | openssl aes-256-cbc -e -a -p -salt -pbkdf2 -iter 15739 -k qk4aX-EfMUa-g4HdF-fjfkU-bbLNx-15739
     *
     * Terminal output:
     *   salt=CC73B7D29FE59CE1
     *   key=31706F84185EA4B5E8E040F2C813F79722F22996B48B82FF98174F887A9B9993
     *   iv =1420310D41FD7F48E5D8722B9AC1C8DD
     *   U2FsdGVkX1/Mc7fSn+Wc4XLwDsmLdR8O7K3bFPpCglA=
     * */
    fun decrypt_AES256CBC_PBKDF2_HMAC_SHA256(
        password: String,
        hashIterations: Int,
        encryptedString: String
    ): String {
        val encryptedBytes = Base64.getDecoder().decode(encryptedString)

        // Salt is bytes 8 - 15
        val salt = encryptedBytes.copyOfRange(8, 16)
//        println("Salt: ${salt.joinToString("") { "%02X".format(it) }}")

        // Derive 48 byte key
        val keySpec = PBEKeySpec(password.toCharArray(), salt, hashIterations, 48 * 8)
        val keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
        val secretKey = keyFactory.generateSecret(keySpec)

        // Decryption Key is bytes 0 - 31 of the derived key
        val key = secretKey.encoded.copyOfRange(0, 32)
//        println("Key: ${key.joinToString("") { "%02X".format(it) }}")

        // Input Vector is bytes 32 - 47 of the derived key
        val iv = secretKey.encoded.copyOfRange(32, 48)
//        println("IV: ${iv.joinToString("") { "%02X".format(it) }}")

        // Cipher Text is bytes 16 - end of the encrypted bytes
        val cipherText = encryptedBytes.copyOfRange(16, encryptedBytes.lastIndex + 1)

        // Decrypt the Cipher Text and manually remove padding after
        val cipher = Cipher.getInstance("AES/CBC/NoPadding")
        cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
        val decrypted = cipher.doFinal(cipherText)
//        println("Decrypted: ${decrypted.joinToString("") { "%02X".format(it) }}")

        // Last byte of the decrypted text is the number of padding bytes needed to remove
        val plaintext = decrypted.copyOfRange(0, decrypted.lastIndex + 1 - decrypted.last().toInt())

        return plaintext.toString(Charsets.UTF_8)
    }
}
Related