Encrypt in java decrypting in openssl
I am using below class to encrypt the data. I want to decrypt the encrypted data by this class using openssl. I am trying to run openssl enc -aes-128-ebc -d -in a.in -out a.out, but I keep getting bad magic number.
public class ByteEncrypter {
public static final String encryptionScheme = "AES";
private SecretKeySpecskeySpec;
private Ciphercipher;
private static final StringUNICODE_FORMAT= "UTF8";
public ByteEncrypter( String encryptionKey )
{
if ( encryptionKey == null )
throw new IllegalArgumentException( "encryption key was null" );
try
{
byte[] keyAsBytes = encryptionKey.getBytes( UNICODE_FORMAT );
skeySpec = new SecretKeySpec(keyAsBytes, encryptionScheme);
cipher = Cipher.getInstance( encryptionScheme );
}
catch (Exception e){
if(Debug.pvshDebugLevel > 0 ) System.out.println("Failed to create ByeEncrypter");
e.printStackTrace();
}
}
public byte [] encrypt(byte [] data) throws ArchiveServiceExceptionImpl{
if (null == data || data.length <=0){
throw new IllegalArgumentException( "encryption key was null" );
}
byte[] encrypted = null;
try{
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encrypted = cipher.doFinal(data);
}catch(Exception e){
if(Debug.pvshDebugLevel > 0 ) System.out.println("Failed to encrypt ");
e.printStackTrace();
}
return encrypted;
}
public byte [] decrypt(byte [] data) throws ArchiveServiceExceptionImpl{
if (null == data || data.length <=0){
throw new IllegalArgumentException( "encryption key was null" );
}
byte[] decrypted = null;
try{
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
decrypted = cipher.doFinal(data);
}catch(Exception e){
if(Debug.pvshDebugLevel > 0 ) System.out.println("Failed to Decrypt");
e.printStackTrace();
}
return decrypted;
}
}
1) You will need to convert your encryption key to hex and use the hex value with the -K option in openssl.
2) should that not be -aes-128-ecb .
So my code needs to be changed to something like this ? Or is there a better way of doing it.
public ByteEncrypter( String encryptionKey )
{
if ( encryptionKey == null )
throw new IllegalArgumentException( "encryption key was null" );
try
{
byte[] keyAsBytes = string2Hex(encryptionKey).getBytes( UNICODE_FORMAT );
skeySpec = new SecretKeySpec(keyAsBytes, encryptionScheme);
cipher = Cipher.getInstance( encryptionScheme );
}
catch (Exception e){
if(Debug.pvshDebugLevel > 0 ) System.out.println("Failed to create ByeEncrypter");
e.printStackTrace();
}
}
private static String string2Hex(String foo){
char[] chars = foo.toCharArray();
StringBuffer output = new StringBuffer();
for(int i = 0; i < chars.length; i++){
output.append(Integer.toHexString((int)char));
}
return output.toString();
}
- Also, in openssl command do I need to use value returned by string2Hex(encryptionKey) ?
If your AES key is 16 or 24 or 32 bytes then use those bytes directly in the Java but hex encode them and use them with the -K option in openssl. Yes, capital K. Check the man page for openssl.
May be I am not exactly getting it. I changed following line:
String encryptionKey = "1234567891234567";
encryptionKey.getBytes( "UTF8" );
to
encryptionKey.getBytes( "UTF16" );
Now I am getting:
java.security.InvalidKeyException: Invalid AES key length: 272
at com.sun.crypto.provider.AESCipher.engineGetKeySize(DashoA12275)
at javax.crypto.Cipher.b(DashoA12275)
at javax.crypto.Cipher.a(DashoA12275)
at javax.crypto.Cipher.a(DashoA12275)
at javax.crypto.Cipher.a(DashoA12275)
at javax.crypto.Cipher.init(DashoA12275)
at javax.crypto.Cipher.init(DashoA12275)
I could make it work after I changed the following:
1. I changed the encryption scheme from AES to AES/CBC/PKCS5PAdding
2. Added Iv as a parameter to cipher.init
then it worked with -aes-128-cbc with -K and -iv option
but I couldn't get it to work with -aes-128-ecb. I don't know why.
> May be I am not exactly getting it. I changed
> following line:
> String encryptionKey = "1234567891234567";
> encryptionKey.getBytes( "UTF8" );
> o
> encryptionKey.getBytes( "UTF16" );
>
Assume in Java your your key bytes arebyte[] keyBytes =
{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
then your key will be spedified in openssl as
openssl ....-K 0102030405060708090a0b0c0d0e0f ...
Actually, before posting my question yesterday I had already tried what's being suggested by you. But, that doesn't work with openssl, unless I change my algorithm to "AES/CBC/PKCS5Padding" and add IV parameter, then use the hex key and hex iv in openssl.
I don't know why I can't use openssl with just AES and no iv parameter ?
> Actually, before posting my question yesterday I had
> already tried what's being suggested by you. But,
> that doesn't work with openssl, unless I change my
> algorithm to "AES/CBC/PKCS5Padding" and add IV
> parameter, then use the hex key and hex iv in
> openssl.
Works for me! One of my standard examples is AES encryption using ECB mode in Java and decryption in openssl.
CBC mode is just as easy.
>
> I don't know why I can't use openssl with just AES
> and no iv parameter ?
Since I can do it without any problem and I can't see your Java code (other than your original posting which was very wrong) or your openssl command I can't help.
Create a stand alone example of your Java ECB mode AES encryption and post it.
Here is standalone program:
import javax.crypto.*;
import java.io.*;
import javax.crypto.spec.*;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class ByteEncrypter1 {
public static final String encryptionScheme = "AES";
private SecretKeySpecskeySpec;
private Cipher cipher;
private static final StringUNICODE_FORMAT= "UTF8";
private IvParameterSpec Iv ;
public ByteEncrypter1( String encryptionKey )
{
try{
byte[] keyAsBytes = {0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50};
skeySpec = new SecretKeySpec(keyAsBytes, encryptionScheme);
cipher = Cipher.getInstance( encryptionScheme );
}
catch (Exception e){
System.out.println("Failed to create ByeEncrypter");
e.printStackTrace();
}
}
public void encrypt(byte [] data) {
if (null == data || data.length <=0){
throw new IllegalArgumentException( "encryption key was null" );
}
byte[] encrypted = null;
try{
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
CipherOutputStream ci = new CipherOutputStream(new FileOutputStream("b.enc"), cipher);
ci.write(data);
ci.close();
}catch(Exception e){
System.out.println("Failed to encrypt");
e.printStackTrace();
}
}
private static String bytes2String( byte[] bytes ) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < bytes.length; i++)
{
stringBuffer.append( (char) bytes );
}
return stringBuffer.toString();
}
public static void main (String ...a){
ByteEncrypter1 b = new ByteEncrypter1 ("ABCDEFGHIJKLMNOP");
b.encrypt("ADDDDDDDFFDDFFFFGGDDDDDDDDDDDDZ".getBytes());
}
}
- Here is openssl command
openssl enc -d -aes-128-ecb -in b.enc -out b.dec -K 4142434445464748494a4b4c4d4e4f50
Thanks for your help
What is the purpose of your bytes2String(() method? It does not seem to be used.
openssl for some reason insists on an iv even thought it does not need one for ecb mode. This silly behavior is not peculiar to openssl - the mcrypt libraries also seem to need one.
You have a lot or redundant code in your stand alone example. I have trimmed it down to
import javax.crypto.*;
import java.io.*;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class ByteEncrypter1
{
public static final String encryptionScheme = "AES";
private SecretKeySpec skeySpec;
private Cipher cipher;
private static final String UNICODE_FORMAT = "UTF8";
public ByteEncrypter1()
{
try
{
byte[] keyAsBytes = {0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50};
skeySpec = new SecretKeySpec(keyAsBytes, encryptionScheme);
cipher = Cipher.getInstance( encryptionScheme );
}
catch (Exception e)
{
System.out.println("Failed to create ByeEncrypter");
e.printStackTrace();
}
}
public void encrypt(byte [] data)
{
if (null == data || data.length <=0)
{
throw new IllegalArgumentException( "encryption key was null" );
}
try
{
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
CipherOutputStream ci = new CipherOutputStream(new FileOutputStream("/home/sabre/b.enc"), cipher);
ci.write(data);
ci.close();
}
catch(Exception e)
{
System.out.println("Failed to encrypt");
e.printStackTrace();
}
}
public static void main(String ...a)
{
ByteEncrypter1 b = new ByteEncrypter1();
b.encrypt("ADDDDDDDFFDDFFFFGGDDDDDDDDDDDDZ".getBytes());
}
}
with the openssl command being
openssl enc -d -aes-128-ecb -iv 0 -in b.enc -out b.dec -K 4142434445464748494a4b4c4d4e4f50
The iv is a dummy iv and a few tests show that the value is not used and as long as you provide a value the decrypted file is correct.
P.S. The text of your encryption exception is misleading.
I gave a sigh with the fact that I was missing -iv 0. I should have tried that. Thanks a lot for your help.