Encrypt in openssl decrypt in Java

I am fairly new to JCA and have a question regarding encrypting a file using openSSL and decrypting using java.

The openssl command used to generate the base64 encoded output is:

openssl enc -a -in tmp -out tmp1 -e -K 30313233343536373839414243444546 -iv 3031323334353637 -nosalt -des-ede3-cbc

As is apparent from the command, i need to use des-ede3 in cbc mode to encrypt the file. Encoding in base64 is not so much a requirement but did that so that i don't have to deal with reading binary file (as i wasn't sure how many bytes i am decrypting at a time).

On the java side, the code looks something like this.

package mystuff.util;

import java.security.InvalidAlgorithmParameterException;

import java.security.InvalidKeyException;

import java.security.NoSuchAlgorithmException;

import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;

import javax.crypto.Cipher;

import javax.crypto.IllegalBlockSizeException;

import javax.crypto.NoSuchPaddingException;

import javax.crypto.SecretKey;

import javax.crypto.SecretKeyFactory;

import javax.crypto.spec.DESKeySpec;

import javax.crypto.spec.DESedeKeySpec;

import javax.crypto.spec.IvParameterSpec;

import sun.misc.BASE64Decoder;

public class DecryptOpenSSL

{

public String decryptData(String encryptedData)

throws BadPaddingException, IllegalBlockSizeException, Exception

{

// decrypting the data

byte[] actualValue = getCipher("DECRYPT").doFinal(new BASE64Decoder()

.decodeBuffer(encryptedData));

// return decrypted value

return new String(actualValue, "UTF-8");

}

private Cipher getCipher(String mode)

throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException,

NoSuchPaddingException,InvalidAlgorithmParameterException

{

// encryption Key used in openSSL command

byte[] encryptKey = "30313233343536373839414243444546".getBytes();

// IV stuff, hex representation of the IV used in openSSL

IvParameterSpec IvParameters = new IvParameterSpec(new byte[]

{0X30,0X31,0X32,0X33,0X34,0X35,0X36,0X37});

// creating a DES key spec from the byte array key

DESedeKeySpec spec = new DESedeKeySpec(encryptKey);

// initializing secret key factory for generating DES keys

SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");

// creating a DES SecretKey object

SecretKey theKey = keyFactory.generateSecret(spec);

// obtaining a DES Cipher object

Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");

// Initializing the cipher and put it into decrypt mode

cipher.init(Cipher.DECRYPT_MODE, theKey, IvParameters);

return cipher;

}

public static void main(String args[])

{

try

{

DecryptOpenSSL ds = new DecryptOpenSSL();

System.out.println(ds.decryptData("V9DxfBvvZTijadFZqi87to9jPHN+Ecru"));

}

catch (Exception e)

{

e.printStackTrace();

}

}

}

[3150 byte] By [ihtcdinga] at [2007-11-26 22:59:48]
# 1
Forgot to mention that when i run the java code, i get some junk binary data in the output. There's obviously one or more thing i am missing but am not sure what it is.
ihtcdinga at 2007-7-10 12:26:23 > top of Java-index,Security,Cryptography...
# 2

Got it to work, the byte[] encryptKey = "30313233343536373839414243444546".getBytes(); was obviously incorrect, the command line argument to openSSL is a 24 byte hex key and i was just converting the string to bytes which was incorrect. In the revised code, the byte[] array looks something like this.

byte[] encryptKey = new byte[]{0X30,0X31,0X32,0X33,0X34,0X35,0X36,0X37,0X38,0X39,0X41,0X42,0X43,0X44,0X45,0X46,0X47,0X48,0X49,0X51,0X52,0X53,0X54,0X55};

Corresponding openSSL command also has a hex key with 24 bytes.

ihtcdinga at 2007-7-10 12:26:23 > top of Java-index,Security,Cryptography...
# 3

I am a little surprised that you don't get an illegal key size exception from the code

byte[] encryptKey = "30313233343536373839414243444546".getBytes();

<snip>

DESedeKeySpec spec = new DESedeKeySpec(encryptKey);

since encryptkey content will be 32 bytes and the Java DEDede key is 24 bytes.

if you look at the openssl man page you will see the the -K option take the key as a hex string so your openssl key is actually 16 bytes hex encoded. Therefore,

your DESede key should be constructed from the HEX decode string and not from the getBytes().

There is a further complication. openssl has to modify the key to make it up to 24 bytes and it does this by appending the first 8 bytes to the and of the key. If you original 16 key bytes are

XXXXXXXXYYYYYYYY

then openssl converts this to

XXXXXXXXYYYYYYYYXXXXXXXX. You will have to do the same in your Java.

To summarize - to create the Java key, hex decode the -K value and append the first 8 bytes of the results to the key to make 24 bytes.

sabre150a at 2007-7-10 12:26:23 > top of Java-index,Security,Cryptography...
# 4
:( You solved the problem in the 6 minutes it took me to type my response!
sabre150a at 2007-7-10 12:26:23 > top of Java-index,Security,Cryptography...
# 5

Thanks sabre for the reply. Just a very quick question on the -K and -iv option. I used both of these options purely based on your responses to one of the earlier posts along the same lines. I was originally trying -k option. I know that in CBC mode you need to specify the iv but i am not quite clear on when to use -k or -K option.

ihtcdinga at 2007-7-10 12:26:23 > top of Java-index,Security,Cryptography...
# 6

The -K indicates that what follows is the HEX representation of the key bytes. The -k indicates that the key bytes are obtained by some hashing type process.

Unless you are willing to spend time working out what the hashing process is so that you can duplicate this in Java to produce the key bytes then you do best to you the -K option when all you have to do is HEX decode the bytes and append the first 8.

sabre150a at 2007-7-10 12:26:23 > top of Java-index,Security,Cryptography...
# 7
This thread helped me a lot. Thanks,Here is a tip to get hex String from bytes.new BigInteger(byteArray).toString(16)
TIrthoa at 2007-7-10 12:26:23 > top of Java-index,Security,Cryptography...
# 8
> This thread helped me a lot. Thanks,> > Here is a tip to get hex String from bytes.> > new BigInteger(byteArray).toString(16)What happens if the leading byte contains the value between 0x80 and 0xff ?
sabre150a at 2007-7-10 12:26:23 > top of Java-index,Security,Cryptography...